aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2020-01-07 11:18:04 +0000
committerDaniel Mueller <deso@posteo.net>2020-01-08 09:20:25 -0800
commit5e20a29b4fdc8a2d442d1093681b396dcb4b816b (patch)
tree55ab083fa8999d2ccbb5e921c1ffe52560dca152
parent203e691f46d591a2cc8acdfd850fa9f5b0fb8a98 (diff)
downloadnitrocli-5e20a29b4fdc8a2d442d1093681b396dcb4b816b.tar.gz
nitrocli-5e20a29b4fdc8a2d442d1093681b396dcb4b816b.tar.bz2
Add structopt dependency in version 0.3.7
This patch series replaces argparse with structopt in the argument handling code. As a first step, we need structopt as a dependency. Import subrepo structopt/:structopt at efbdda4753592e27bc430fb01f7b9650b2f3174d Import subrepo bitflags/:bitflags at 30668016aca6bd3b02c766e8347e0b4080d4c296 Import subrepo clap/:clap at 784524f7eb193e35f81082cc69454c8c21b948f7 Import subrepo heck/:heck at 093d56fbf001e1506e56dbfa38631d99b1066df1 Import subrepo proc-macro-error/:proc-macro-error at 6c4cfe79a622c5de8ae68557993542be46eacae2 Import subrepo proc-macro2/:proc-macro2 at d5d48eddca4566e5438e8a2cbed4a74e049544de Import subrepo quote/:quote at 727436c6c137b20f0f34dde5d8fda2679b9747ad Import subrepo rustversion/:rustversion at 0c5663313516263059ce9059ef81fc7a1cf655ca Import subrepo syn-mid/:syn-mid at 5d3d85414a9e6674e1857ec22a87b96e04a6851a Import subrepo syn/:syn at e87c27e87f6f4ef8919d0372bdb056d53ef0d8f3 Import subrepo textwrap/:textwrap at abcd618beae3f74841032aa5b53c1086b0a57ca2 Import subrepo unicode-segmentation/:unicode-segmentation at 637c9874c4fe0c205ff27787faf150a40295c6c3 Import subrepo unicode-width/:unicode-width at 3033826f8bf05e82724140a981d5941e48fce393 Import subrepo unicode-xid/:unicode-xid at 4baae9fffb156ba229665b972a9cd5991787ceb7
-rw-r--r--bitflags/.gitignore4
-rw-r--r--bitflags/.travis.yml39
-rw-r--r--bitflags/CHANGELOG.md149
-rw-r--r--bitflags/CODE_OF_CONDUCT.md73
-rw-r--r--bitflags/Cargo.toml37
-rw-r--r--bitflags/LICENSE-APACHE201
-rw-r--r--bitflags/LICENSE-MIT25
-rw-r--r--bitflags/README.md34
-rw-r--r--bitflags/bors.toml3
-rw-r--r--bitflags/build.rs44
-rw-r--r--bitflags/src/example_generated.rs14
-rw-r--r--bitflags/src/lib.rs1430
-rw-r--r--bitflags/test_suite/Cargo.toml13
-rw-r--r--bitflags/test_suite/tests/compile-fail/private_flags.rs20
-rw-r--r--bitflags/test_suite/tests/compiletest.rs33
-rw-r--r--bitflags/test_suite/tests/conflicting_trait_impls.rs17
-rw-r--r--bitflags/test_suite/tests/external.rs19
-rw-r--r--bitflags/test_suite/tests/external_no_std.rs21
-rw-r--r--bitflags/test_suite/tests/i128_bitflags.rs30
-rw-r--r--bitflags/test_suite/tests/serde.rs35
-rw-r--r--clap/.appveyor.yml17
-rw-r--r--clap/.clog.toml14
-rw-r--r--clap/.github/CONTRIBUTING.md115
-rw-r--r--clap/.github/ISSUE_TEMPLATE.md46
-rw-r--r--clap/.gitignore27
-rw-r--r--clap/.mention-bot9
-rw-r--r--clap/.travis.yml59
-rw-r--r--clap/CHANGELOG.md2855
-rw-r--r--clap/CONTRIBUTORS.md91
-rw-r--r--clap/Cargo.toml91
-rw-r--r--clap/LICENSE-MIT21
-rw-r--r--clap/README.md542
-rw-r--r--clap/SPONSORS.md17
-rw-r--r--clap/benches/01_default.rs18
-rw-r--r--clap/benches/02_simple.rs114
-rw-r--r--clap/benches/03_complex.rs230
-rw-r--r--clap/benches/04_new_help.rs198
-rw-r--r--clap/benches/05_ripgrep.rs777
-rw-r--r--clap/benches/06_rustup.rs458
-rw-r--r--clap/clap-perf/clap_perf.dat8
-rw-r--r--clap/clap-perf/clap_perf.pngbin0 -> 9702 bytes
-rwxr-xr-xclap/clap-perf/plot_perf.gp26
-rw-r--r--clap/clap-test.rs86
-rw-r--r--clap/clap_dep_graph.dot41
-rw-r--r--clap/clap_dep_graph.pngbin0 -> 96195 bytes
-rw-r--r--clap/examples/01a_quick_example.rs79
-rw-r--r--clap/examples/01b_quick_example.rs93
-rw-r--r--clap/examples/01c_quick_example.rs75
-rw-r--r--clap/examples/02_apps.rs30
-rw-r--r--clap/examples/03_args.rs84
-rw-r--r--clap/examples/04_using_matches.rs54
-rw-r--r--clap/examples/05_flag_args.rs56
-rw-r--r--clap/examples/06_positional_args.rs56
-rw-r--r--clap/examples/07_option_args.rs71
-rw-r--r--clap/examples/08_subcommands.rs57
-rw-r--r--clap/examples/09_auto_version.rs29
-rw-r--r--clap/examples/10_default_values.rs40
-rw-r--r--clap/examples/11_only_specific_values.rs33
-rw-r--r--clap/examples/12_typed_values.rs50
-rw-r--r--clap/examples/13a_enum_values_automatic.rs68
-rw-r--r--clap/examples/13b_enum_values_manual.rs54
-rw-r--r--clap/examples/14_groups.rs87
-rw-r--r--clap/examples/15_custom_validator.rs37
-rw-r--r--clap/examples/16_app_settings.rs41
-rw-r--r--clap/examples/17_yaml.rs53
-rw-r--r--clap/examples/17_yaml.yml97
-rw-r--r--clap/examples/18_builder_macro.rs84
-rw-r--r--clap/examples/19_auto_authors.rs15
-rw-r--r--clap/examples/20_subcommands.rs143
-rw-r--r--clap/examples/21_aliases.rs39
-rw-r--r--clap/examples/22_stop_parsing_with_--.rs25
-rw-r--r--clap/justfile39
-rw-r--r--clap/rustfmt.toml4
-rw-r--r--clap/src/app/help.rs1028
-rw-r--r--clap/src/app/meta.rs33
-rw-r--r--clap/src/app/mod.rs1839
-rw-r--r--clap/src/app/parser.rs2167
-rw-r--r--clap/src/app/settings.rs1174
-rw-r--r--clap/src/app/usage.rs479
-rw-r--r--clap/src/app/validator.rs573
-rw-r--r--clap/src/args/any_arg.rs74
-rw-r--r--clap/src/args/arg.rs3954
-rw-r--r--clap/src/args/arg_builder/base.rs38
-rw-r--r--clap/src/args/arg_builder/flag.rs159
-rw-r--r--clap/src/args/arg_builder/mod.rs13
-rw-r--r--clap/src/args/arg_builder/option.rs244
-rw-r--r--clap/src/args/arg_builder/positional.rs229
-rw-r--r--clap/src/args/arg_builder/switched.rs38
-rw-r--r--clap/src/args/arg_builder/valued.rs67
-rw-r--r--clap/src/args/arg_matcher.rs218
-rw-r--r--clap/src/args/arg_matches.rs963
-rw-r--r--clap/src/args/group.rs635
-rw-r--r--clap/src/args/macros.rs109
-rw-r--r--clap/src/args/matched_arg.rs24
-rw-r--r--clap/src/args/mod.rs21
-rw-r--r--clap/src/args/settings.rs231
-rw-r--r--clap/src/args/subcommand.rs66
-rw-r--r--clap/src/completions/bash.rs219
-rw-r--r--clap/src/completions/elvish.rs126
-rw-r--r--clap/src/completions/fish.rs99
-rw-r--r--clap/src/completions/macros.rs28
-rw-r--r--clap/src/completions/mod.rs179
-rw-r--r--clap/src/completions/powershell.rs139
-rw-r--r--clap/src/completions/shell.rs52
-rw-r--r--clap/src/completions/zsh.rs472
-rw-r--r--clap/src/errors.rs912
-rw-r--r--clap/src/fmt.rs189
-rw-r--r--clap/src/lib.rs629
-rw-r--r--clap/src/macros.rs1108
-rw-r--r--clap/src/map.rs74
-rw-r--r--clap/src/osstringext.rs119
-rw-r--r--clap/src/strext.rs16
-rw-r--r--clap/src/suggestions.rs147
-rw-r--r--clap/src/usage_parser.rs1347
-rw-r--r--clap/tests/app.yml121
-rw-r--r--clap/tests/app_settings.rs965
-rw-r--r--clap/tests/arg_aliases.rs200
-rw-r--r--clap/tests/borrowed.rs19
-rw-r--r--clap/tests/completions.rs883
-rw-r--r--clap/tests/conflicts.rs102
-rw-r--r--clap/tests/default_vals.rs498
-rw-r--r--clap/tests/delimiters.rs139
-rw-r--r--clap/tests/derive_order.rs245
-rw-r--r--clap/tests/env.rs263
-rw-r--r--clap/tests/example1_tmpl_full.txt15
-rw-r--r--clap/tests/example1_tmpl_simple.txt8
-rw-r--r--clap/tests/flags.rs147
-rw-r--r--clap/tests/global_args.rs37
-rw-r--r--clap/tests/groups.rs207
-rw-r--r--clap/tests/help.rs1205
-rw-r--r--clap/tests/hidden_args.rs178
-rw-r--r--clap/tests/indices.rs175
-rwxr-xr-xclap/tests/macros.rs391
-rw-r--r--clap/tests/multiple_occurrences.rs75
-rw-r--r--clap/tests/multiple_values.rs1122
-rw-r--r--clap/tests/opts.rs461
-rw-r--r--clap/tests/positionals.rs274
-rw-r--r--clap/tests/posix_compatible.rs292
-rw-r--r--clap/tests/possible_values.rs266
-rw-r--r--clap/tests/propagate_globals.rs148
-rw-r--r--clap/tests/require.rs688
-rw-r--r--clap/tests/subcommands.rs216
-rw-r--r--clap/tests/template_help.rs117
-rw-r--r--clap/tests/tests.rs435
-rw-r--r--clap/tests/unique_args.rs22
-rw-r--r--clap/tests/utf8.rs223
-rw-r--r--clap/tests/version-numbers.rs12
-rw-r--r--clap/tests/version.rs58
-rw-r--r--clap/tests/yaml.rs40
-rw-r--r--heck/.gitignore2
-rw-r--r--heck/Cargo.toml14
-rw-r--r--heck/LICENSE-APACHE201
-rw-r--r--heck/LICENSE-MIT25
-rw-r--r--heck/README.md56
-rw-r--r--heck/no_step_on_snek.pngbin0 -> 43512 bytes
-rw-r--r--heck/src/camel.rs52
-rw-r--r--heck/src/kebab.rs51
-rw-r--r--heck/src/lib.rs165
-rw-r--r--heck/src/mixed.rs56
-rw-r--r--heck/src/shouty_snake.rs67
-rw-r--r--heck/src/snake.rs79
-rw-r--r--heck/src/title.rs52
-rw-r--r--nitrocli/CHANGELOG.md5
-rw-r--r--nitrocli/Cargo.lock119
-rw-r--r--nitrocli/Cargo.toml22
-rw-r--r--proc-macro-error/.gitignore4
-rw-r--r--proc-macro-error/.gitlab-ci.yml54
-rw-r--r--proc-macro-error/.travis.yml19
-rw-r--r--proc-macro-error/CHANGELOG.md86
-rw-r--r--proc-macro-error/Cargo.toml7
-rw-r--r--proc-macro-error/LICENSE-APACHE201
-rw-r--r--proc-macro-error/LICENSE-MIT21
-rw-r--r--proc-macro-error/README.md206
-rw-r--r--proc-macro-error/proc-macro-error-attr/Cargo.toml18
-rw-r--r--proc-macro-error/proc-macro-error-attr/src/lib.rs162
-rw-r--r--proc-macro-error/proc-macro-error/Cargo.toml26
-rw-r--r--proc-macro-error/proc-macro-error/build.rs11
-rw-r--r--proc-macro-error/proc-macro-error/src/dummy.rs136
-rw-r--r--proc-macro-error/proc-macro-error/src/lib.rs514
-rw-r--r--proc-macro-error/proc-macro-error/src/macros.rs257
-rw-r--r--proc-macro-error/proc-macro-error/src/nightly.rs49
-rw-r--r--proc-macro-error/proc-macro-error/src/stable.rs26
-rw-r--r--proc-macro-error/test-crate/Cargo.toml20
-rw-r--r--proc-macro-error/test-crate/src/lib.rs123
-rw-r--r--proc-macro-error/test-crate/tests/macro-errors.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ok.rs9
-rw-r--r--proc-macro-error/test-crate/tests/ui/abort.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ui/abort.stderr8
-rw-r--r--proc-macro-error/test-crate/tests/ui/call_site.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ui/call_site.stderr8
-rw-r--r--proc-macro-error/test-crate/tests/ui/direct_abort.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ui/direct_abort.stderr5
-rw-r--r--proc-macro-error/test-crate/tests/ui/dummy.rs16
-rw-r--r--proc-macro-error/test-crate/tests/ui/dummy.stderr5
-rw-r--r--proc-macro-error/test-crate/tests/ui/multi-error.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ui/multi-error.stderr32
-rw-r--r--proc-macro-error/test-crate/tests/ui/not_proc_macro.rs4
-rw-r--r--proc-macro-error/test-crate/tests/ui/not_proc_macro.stderr8
-rw-r--r--proc-macro-error/test-crate/tests/ui/option_expect.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ui/option_expect.stderr5
-rw-r--r--proc-macro-error/test-crate/tests/ui/result_expect.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ui/result_expect.stderr5
-rw-r--r--proc-macro-error/test-crate/tests/ui/result_unwrap.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ui/result_unwrap.stderr5
-rw-r--r--proc-macro-error/test-crate/tests/ui/unknown_setting.rs4
-rw-r--r--proc-macro-error/test-crate/tests/ui/unknown_setting.stderr5
-rw-r--r--proc-macro-error/test-crate/tests/ui/unrelated_panic.rs6
-rw-r--r--proc-macro-error/test-crate/tests/ui/unrelated_panic.stderr7
-rw-r--r--proc-macro2/.gitignore3
-rw-r--r--proc-macro2/.travis.yml36
-rw-r--r--proc-macro2/Cargo.toml57
-rw-r--r--proc-macro2/LICENSE-APACHE201
-rw-r--r--proc-macro2/LICENSE-MIT25
-rw-r--r--proc-macro2/README.md93
-rw-r--r--proc-macro2/benches/bench-libproc-macro/Cargo.toml13
-rw-r--r--proc-macro2/benches/bench-libproc-macro/README.md10
-rw-r--r--proc-macro2/benches/bench-libproc-macro/lib.rs49
-rw-r--r--proc-macro2/benches/bench-libproc-macro/main.rs3
-rw-r--r--proc-macro2/build.rs129
-rw-r--r--proc-macro2/src/fallback.rs1458
-rw-r--r--proc-macro2/src/lib.rs1199
-rw-r--r--proc-macro2/src/strnom.rs391
-rw-r--r--proc-macro2/src/wrapper.rs927
-rw-r--r--proc-macro2/tests/features.rs8
-rw-r--r--proc-macro2/tests/marker.rs59
-rw-r--r--proc-macro2/tests/test.rs466
-rw-r--r--quote/.gitignore2
-rw-r--r--quote/.travis.yml18
-rw-r--r--quote/Cargo.toml32
-rw-r--r--quote/LICENSE-APACHE201
-rw-r--r--quote/LICENSE-MIT25
-rw-r--r--quote/README.md237
-rw-r--r--quote/benches/bench.rs193
-rw-r--r--quote/src/ext.rs112
-rw-r--r--quote/src/format.rs164
-rw-r--r--quote/src/ident_fragment.rs72
-rw-r--r--quote/src/lib.rs948
-rw-r--r--quote/src/runtime.rs373
-rw-r--r--quote/src/spanned.rs42
-rw-r--r--quote/src/to_tokens.rs209
-rw-r--r--quote/tests/compiletest.rs6
-rw-r--r--quote/tests/test.rs429
-rw-r--r--quote/tests/ui/does-not-have-iter-interpolated-dup.rs9
-rw-r--r--quote/tests/ui/does-not-have-iter-interpolated-dup.stderr11
-rw-r--r--quote/tests/ui/does-not-have-iter-interpolated.rs9
-rw-r--r--quote/tests/ui/does-not-have-iter-interpolated.stderr11
-rw-r--r--quote/tests/ui/does-not-have-iter-separated.rs5
-rw-r--r--quote/tests/ui/does-not-have-iter-separated.stderr11
-rw-r--r--quote/tests/ui/does-not-have-iter.rs5
-rw-r--r--quote/tests/ui/does-not-have-iter.stderr11
-rw-r--r--quote/tests/ui/not-quotable.rs7
-rw-r--r--quote/tests/ui/not-quotable.stderr10
-rw-r--r--quote/tests/ui/not-repeatable.rs7
-rw-r--r--quote/tests/ui/not-repeatable.stderr14
-rw-r--r--quote/tests/ui/wrong-type-span.rs7
-rw-r--r--quote/tests/ui/wrong-type-span.stderr10
-rw-r--r--rustversion/.gitignore3
-rw-r--r--rustversion/.travis.yml17
-rw-r--r--rustversion/Cargo.toml21
-rw-r--r--rustversion/LICENSE-APACHE201
-rw-r--r--rustversion/LICENSE-MIT23
-rw-r--r--rustversion/README.md138
-rw-r--r--rustversion/src/attr.rs35
-rw-r--r--rustversion/src/bound.rs84
-rw-r--r--rustversion/src/date.rs77
-rw-r--r--rustversion/src/expr.rs177
-rw-r--r--rustversion/src/lib.rs254
-rw-r--r--rustversion/src/rustc.rs195
-rw-r--r--rustversion/src/time.rs44
-rw-r--r--rustversion/src/version.rs16
-rw-r--r--structopt/.gitignore6
-rw-r--r--structopt/.travis.yml24
-rw-r--r--structopt/CHANGELOG.md444
-rw-r--r--structopt/Cargo.toml35
-rw-r--r--structopt/LICENSE-APACHE201
-rw-r--r--structopt/LICENSE-MIT21
-rw-r--r--structopt/README.md148
-rw-r--r--structopt/examples/README.md82
-rw-r--r--structopt/examples/after_help.rs19
-rw-r--r--structopt/examples/at_least_two.rs15
-rw-r--r--structopt/examples/basic.rs48
-rw-r--r--structopt/examples/deny_missing_docs.rs51
-rw-r--r--structopt/examples/doc_comments.rs74
-rw-r--r--structopt/examples/enum_in_args.rs25
-rw-r--r--structopt/examples/enum_tuple.rs26
-rw-r--r--structopt/examples/env.rs26
-rw-r--r--structopt/examples/example.rs54
-rw-r--r--structopt/examples/flatten.rs29
-rw-r--r--structopt/examples/gen_completions.rs26
-rw-r--r--structopt/examples/git.rs35
-rw-r--r--structopt/examples/group.rs31
-rw-r--r--structopt/examples/keyvalue.rs36
-rw-r--r--structopt/examples/negative_flag.rs15
-rw-r--r--structopt/examples/no_version.rs17
-rw-r--r--structopt/examples/rename_all.rs74
-rw-r--r--structopt/examples/skip.rs47
-rw-r--r--structopt/examples/subcommand_aliases.rs21
-rw-r--r--structopt/examples/true_or_false.rs41
-rw-r--r--structopt/link-check-headers.json14
-rw-r--r--structopt/src/lib.rs1015
-rw-r--r--structopt/structopt-derive/Cargo.toml27
-rw-r--r--structopt/structopt-derive/LICENSE-APACHE201
-rw-r--r--structopt/structopt-derive/LICENSE-MIT21
-rw-r--r--structopt/structopt-derive/src/attrs.rs620
-rw-r--r--structopt/structopt-derive/src/doc_comments.rs103
-rw-r--r--structopt/structopt-derive/src/lib.rs667
-rw-r--r--structopt/structopt-derive/src/parse.rs304
-rw-r--r--structopt/structopt-derive/src/spanned.rs101
-rw-r--r--structopt/structopt-derive/src/ty.rs108
-rw-r--r--structopt/tests/argument_naming.rs311
-rw-r--r--structopt/tests/arguments.rs86
-rw-r--r--structopt/tests/author_version_about.rs46
-rw-r--r--structopt/tests/custom-string-parsers.rs306
-rw-r--r--structopt/tests/deny-warnings.rs47
-rw-r--r--structopt/tests/doc-comments-help.rs162
-rw-r--r--structopt/tests/explicit_name_no_renaming.rs32
-rw-r--r--structopt/tests/flags.rs162
-rw-r--r--structopt/tests/flatten.rs95
-rw-r--r--structopt/tests/issues.rs67
-rw-r--r--structopt/tests/macro-errors.rs13
-rw-r--r--structopt/tests/nested-subcommands.rs193
-rw-r--r--structopt/tests/non_literal_attributes.rs147
-rw-r--r--structopt/tests/options.rs336
-rw-r--r--structopt/tests/privacy.rs32
-rw-r--r--structopt/tests/raw_bool_literal.rs29
-rw-r--r--structopt/tests/raw_idents.rs17
-rw-r--r--structopt/tests/rename_all_env.rs46
-rw-r--r--structopt/tests/skip.rs148
-rw-r--r--structopt/tests/special_types.rs73
-rw-r--r--structopt/tests/subcommands.rs213
-rw-r--r--structopt/tests/ui/bool_default_value.rs21
-rw-r--r--structopt/tests/ui/bool_default_value.stderr5
-rw-r--r--structopt/tests/ui/bool_required.rs21
-rw-r--r--structopt/tests/ui/bool_required.stderr5
-rw-r--r--structopt/tests/ui/flatten_and_doc.rs30
-rw-r--r--structopt/tests/ui/flatten_and_doc.stderr5
-rw-r--r--structopt/tests/ui/flatten_and_methods.rs29
-rw-r--r--structopt/tests/ui/flatten_and_methods.stderr5
-rw-r--r--structopt/tests/ui/flatten_and_parse.rs29
-rw-r--r--structopt/tests/ui/flatten_and_parse.stderr5
-rw-r--r--structopt/tests/ui/non_existent_attr.rs21
-rw-r--r--structopt/tests/ui/non_existent_attr.stderr5
-rw-r--r--structopt/tests/ui/opt_opt_nonpositional.rs20
-rw-r--r--structopt/tests/ui/opt_opt_nonpositional.stderr5
-rw-r--r--structopt/tests/ui/opt_vec_nonpositional.rs20
-rw-r--r--structopt/tests/ui/opt_vec_nonpositional.stderr5
-rw-r--r--structopt/tests/ui/option_default_value.rs21
-rw-r--r--structopt/tests/ui/option_default_value.stderr5
-rw-r--r--structopt/tests/ui/option_required.rs21
-rw-r--r--structopt/tests/ui/option_required.stderr5
-rw-r--r--structopt/tests/ui/parse_empty_try_from_os.rs21
-rw-r--r--structopt/tests/ui/parse_empty_try_from_os.stderr5
-rw-r--r--structopt/tests/ui/parse_function_is_not_path.rs21
-rw-r--r--structopt/tests/ui/parse_function_is_not_path.stderr5
-rw-r--r--structopt/tests/ui/parse_literal_spec.rs21
-rw-r--r--structopt/tests/ui/parse_literal_spec.stderr5
-rw-r--r--structopt/tests/ui/parse_not_zero_args.rs21
-rw-r--r--structopt/tests/ui/parse_not_zero_args.stderr5
-rw-r--r--structopt/tests/ui/positional_bool.rs10
-rw-r--r--structopt/tests/ui/positional_bool.stderr10
-rw-r--r--structopt/tests/ui/raw.rs25
-rw-r--r--structopt/tests/ui/raw.stderr19
-rw-r--r--structopt/tests/ui/rename_all_wrong_casing.rs21
-rw-r--r--structopt/tests/ui/rename_all_wrong_casing.stderr5
-rw-r--r--structopt/tests/ui/skip_flatten.rs42
-rw-r--r--structopt/tests/ui/skip_flatten.stderr5
-rw-r--r--structopt/tests/ui/skip_subcommand.rs42
-rw-r--r--structopt/tests/ui/skip_subcommand.stderr5
-rw-r--r--structopt/tests/ui/skip_with_other_options.rs15
-rw-r--r--structopt/tests/ui/skip_with_other_options.stderr5
-rw-r--r--structopt/tests/ui/skip_without_default.rs29
-rw-r--r--structopt/tests/ui/skip_without_default.stderr9
-rw-r--r--structopt/tests/ui/struct_flatten.rs21
-rw-r--r--structopt/tests/ui/struct_flatten.stderr5
-rw-r--r--structopt/tests/ui/struct_parse.rs21
-rw-r--r--structopt/tests/ui/struct_parse.stderr5
-rw-r--r--structopt/tests/ui/struct_subcommand.rs21
-rw-r--r--structopt/tests/ui/struct_subcommand.stderr5
-rw-r--r--structopt/tests/ui/structopt_empty_attr.rs22
-rw-r--r--structopt/tests/ui/structopt_empty_attr.stderr5
-rw-r--r--structopt/tests/ui/structopt_name_value_attr.rs22
-rw-r--r--structopt/tests/ui/structopt_name_value_attr.stderr5
-rw-r--r--structopt/tests/ui/subcommand_and_flatten.rs36
-rw-r--r--structopt/tests/ui/subcommand_and_flatten.stderr5
-rw-r--r--structopt/tests/ui/subcommand_and_methods.rs36
-rw-r--r--structopt/tests/ui/subcommand_and_methods.stderr5
-rw-r--r--structopt/tests/ui/subcommand_and_parse.rs36
-rw-r--r--structopt/tests/ui/subcommand_and_parse.stderr5
-rw-r--r--structopt/tests/ui/subcommand_opt_opt.rs36
-rw-r--r--structopt/tests/ui/subcommand_opt_opt.stderr5
-rw-r--r--structopt/tests/ui/subcommand_opt_vec.rs36
-rw-r--r--structopt/tests/ui/subcommand_opt_vec.stderr5
-rw-r--r--structopt/tests/ui/tuple_struct.rs18
-rw-r--r--structopt/tests/ui/tuple_struct.stderr5
-rw-r--r--structopt/tests/utils.rs45
-rw-r--r--syn-mid/.editorconfig22
-rw-r--r--syn-mid/.gitignore6
-rw-r--r--syn-mid/.rustfmt.toml4
-rw-r--r--syn-mid/CHANGELOG.md33
-rw-r--r--syn-mid/Cargo.toml23
-rw-r--r--syn-mid/LICENSE-APACHE202
-rw-r--r--syn-mid/LICENSE-MIT23
-rw-r--r--syn-mid/README.md72
-rw-r--r--syn-mid/azure-pipelines.yml49
-rw-r--r--syn-mid/bors.toml1
-rw-r--r--syn-mid/ci/azure-clippy.yml31
-rw-r--r--syn-mid/ci/azure-install-rust.yml33
-rw-r--r--syn-mid/ci/azure-rustdoc.yml13
-rw-r--r--syn-mid/ci/azure-rustfmt.yml18
-rw-r--r--syn-mid/ci/azure-test.yml34
-rw-r--r--syn-mid/examples/const_fn/Cargo.toml16
-rw-r--r--syn-mid/examples/const_fn/lib.rs31
-rw-r--r--syn-mid/examples/const_fn_test/Cargo.toml9
-rw-r--r--syn-mid/examples/const_fn_test/build.rs16
-rw-r--r--syn-mid/examples/const_fn_test/tests/test.rs25
-rw-r--r--syn-mid/src/arg.rs99
-rw-r--r--syn-mid/src/lib.rs190
-rw-r--r--syn-mid/src/macros.rs107
-rw-r--r--syn-mid/src/pat.rs413
-rw-r--r--syn-mid/src/path.rs50
-rw-r--r--syn/.gitignore3
-rw-r--r--syn/.travis.yml76
-rw-r--r--syn/Cargo.toml72
-rw-r--r--syn/LICENSE-APACHE201
-rw-r--r--syn/LICENSE-MIT23
-rw-r--r--syn/README.md291
-rw-r--r--syn/appveyor.yml16
-rw-r--r--syn/benches/file.rs30
-rw-r--r--syn/benches/rust.rs158
-rw-r--r--syn/build.rs63
-rw-r--r--syn/codegen/Cargo.toml31
-rw-r--r--syn/codegen/README.md12
-rw-r--r--syn/codegen/src/debug.rs308
-rw-r--r--syn/codegen/src/file.rs32
-rw-r--r--syn/codegen/src/fold.rs284
-rw-r--r--syn/codegen/src/full.rs20
-rw-r--r--syn/codegen/src/gen.rs45
-rw-r--r--syn/codegen/src/json.rs18
-rw-r--r--syn/codegen/src/main.rs36
-rw-r--r--syn/codegen/src/operand.rs38
-rw-r--r--syn/codegen/src/parse.rs657
-rw-r--r--syn/codegen/src/version.rs24
-rw-r--r--syn/codegen/src/visit.rs265
-rw-r--r--syn/codegen/src/visit_mut.rs262
-rw-r--r--syn/dev/Cargo.toml22
-rw-r--r--syn/dev/README.md6
-rw-r--r--syn/dev/main.rs4
-rw-r--r--syn/dev/parse.rs18
-rw-r--r--syn/examples/README.md19
-rw-r--r--syn/examples/dump-syntax/Cargo.toml17
-rw-r--r--syn/examples/dump-syntax/README.md28
-rw-r--r--syn/examples/dump-syntax/src/main.rs149
-rw-r--r--syn/examples/heapsize/Cargo.toml2
-rw-r--r--syn/examples/heapsize/README.md72
-rw-r--r--syn/examples/heapsize/example/Cargo.toml9
-rw-r--r--syn/examples/heapsize/example/src/main.rs28
-rw-r--r--syn/examples/heapsize/heapsize/Cargo.toml9
-rw-r--r--syn/examples/heapsize/heapsize/src/lib.rs64
-rw-r--r--syn/examples/heapsize/heapsize_derive/Cargo.toml14
-rw-r--r--syn/examples/heapsize/heapsize_derive/src/lib.rs96
-rw-r--r--syn/examples/lazy-static/Cargo.toml2
-rw-r--r--syn/examples/lazy-static/README.md42
-rw-r--r--syn/examples/lazy-static/example/Cargo.toml10
-rw-r--r--syn/examples/lazy-static/example/src/main.rs20
-rw-r--r--syn/examples/lazy-static/lazy-static/Cargo.toml14
-rw-r--r--syn/examples/lazy-static/lazy-static/src/lib.rs143
-rw-r--r--syn/examples/trace-var/Cargo.toml2
-rw-r--r--syn/examples/trace-var/README.md61
-rw-r--r--syn/examples/trace-var/example/Cargo.toml9
-rw-r--r--syn/examples/trace-var/example/src/main.rs15
-rw-r--r--syn/examples/trace-var/trace-var/Cargo.toml14
-rw-r--r--syn/examples/trace-var/trace-var/src/lib.rs180
-rw-r--r--syn/json/Cargo.toml18
-rw-r--r--syn/json/src/lib.rs214
-rw-r--r--syn/src/attr.rs682
-rw-r--r--syn/src/await.rs2
-rw-r--r--syn/src/bigint.rs66
-rw-r--r--syn/src/buffer.rs382
-rw-r--r--syn/src/custom_keyword.rs252
-rw-r--r--syn/src/custom_punctuation.rs309
-rw-r--r--syn/src/data.rs456
-rw-r--r--syn/src/derive.rs273
-rw-r--r--syn/src/discouraged.rs195
-rw-r--r--syn/src/error.rs357
-rw-r--r--syn/src/export.rs35
-rw-r--r--syn/src/expr.rs3236
-rw-r--r--syn/src/ext.rs135
-rw-r--r--syn/src/file.rs113
-rw-r--r--syn/src/gen/fold.rs3236
-rw-r--r--syn/src/gen/visit.rs3792
-rw-r--r--syn/src/gen/visit_mut.rs3798
-rw-r--r--syn/src/gen_helper.rs154
-rw-r--r--syn/src/generics.rs1152
-rw-r--r--syn/src/group.rs280
-rw-r--r--syn/src/ident.rs101
-rw-r--r--syn/src/item.rs3104
-rw-r--r--syn/src/keyword.rs0
-rw-r--r--syn/src/lib.rs947
-rw-r--r--syn/src/lifetime.rs140
-rw-r--r--syn/src/lit.rs1382
-rw-r--r--syn/src/lookahead.rs168
-rw-r--r--syn/src/mac.rs239
-rw-r--r--syn/src/macros.rs191
-rw-r--r--syn/src/op.rs231
-rw-r--r--syn/src/parse.rs1222
-rw-r--r--syn/src/parse_macro_input.rs110
-rw-r--r--syn/src/parse_quote.rs131
-rw-r--r--syn/src/pat.rs903
-rw-r--r--syn/src/path.rs744
-rw-r--r--syn/src/print.rs16
-rw-r--r--syn/src/punctuated.rs918
-rw-r--r--syn/src/sealed.rs4
-rw-r--r--syn/src/span.rs67
-rw-r--r--syn/src/spanned.rs114
-rw-r--r--syn/src/stmt.rs333
-rw-r--r--syn/src/thread.rs41
-rw-r--r--syn/src/token.rs956
-rw-r--r--syn/src/tt.rs108
-rw-r--r--syn/src/ty.rs1178
-rw-r--r--syn/syn.json5616
-rw-r--r--syn/tests/common/eq.rs459
-rw-r--r--syn/tests/common/mod.rs19
-rw-r--r--syn/tests/common/parse.rs49
-rw-r--r--syn/tests/debug/gen.rs5633
-rw-r--r--syn/tests/debug/mod.rs110
-rw-r--r--syn/tests/features/error.rs1
-rw-r--r--syn/tests/features/mod.rs22
-rw-r--r--syn/tests/macros/mod.rs76
-rw-r--r--syn/tests/repo/mod.rs109
-rw-r--r--syn/tests/repo/progress.rs37
-rw-r--r--syn/tests/test_asyncness.rs39
-rw-r--r--syn/tests/test_attribute.rs296
-rw-r--r--syn/tests/test_derive_input.rs894
-rw-r--r--syn/tests/test_expr.rs37
-rw-r--r--syn/tests/test_generics.rs285
-rw-r--r--syn/tests/test_grouping.rs55
-rw-r--r--syn/tests/test_ident.rs87
-rw-r--r--syn/tests/test_iterators.rs51
-rw-r--r--syn/tests/test_lit.rs184
-rw-r--r--syn/tests/test_meta.rs341
-rw-r--r--syn/tests/test_parse_buffer.rs53
-rw-r--r--syn/tests/test_pat.rs20
-rw-r--r--syn/tests/test_precedence.rs394
-rw-r--r--syn/tests/test_receiver.rs109
-rw-r--r--syn/tests/test_round_trip.rs151
-rw-r--r--syn/tests/test_should_parse.rs47
-rw-r--r--syn/tests/test_size.rs31
-rw-r--r--syn/tests/test_token_trees.rs28
-rw-r--r--syn/tests/test_visibility.rs99
-rw-r--r--syn/tests/zzz_stable.rs33
-rw-r--r--textwrap/.appveyor.yml23
-rw-r--r--textwrap/.circleci/config.yml13
-rw-r--r--textwrap/.codecov.yml13
-rw-r--r--textwrap/.dir-locals.el3
-rw-r--r--textwrap/.gitignore5
-rw-r--r--textwrap/.travis.yml17
-rw-r--r--textwrap/Cargo.toml38
-rw-r--r--textwrap/LICENSE21
-rw-r--r--textwrap/README.md337
-rw-r--r--textwrap/benches/linear.rs122
-rw-r--r--textwrap/examples/layout.rs38
-rw-r--r--textwrap/examples/termwidth.rs41
-rw-r--r--textwrap/src/indentation.rs294
-rw-r--r--textwrap/src/lib.rs987
-rw-r--r--textwrap/src/splitting.rs139
-rw-r--r--textwrap/tests/version-numbers.rs17
-rw-r--r--unicode-segmentation/.gitignore5
-rw-r--r--unicode-segmentation/.travis.yml24
-rw-r--r--unicode-segmentation/COPYRIGHT7
-rw-r--r--unicode-segmentation/Cargo.toml25
-rw-r--r--unicode-segmentation/LICENSE-APACHE201
-rw-r--r--unicode-segmentation/LICENSE-MIT25
-rw-r--r--unicode-segmentation/README.md89
-rwxr-xr-xunicode-segmentation/scripts/unicode.py375
-rwxr-xr-xunicode-segmentation/scripts/unicode_gen_breaktests.py212
-rw-r--r--unicode-segmentation/src/grapheme.rs708
-rw-r--r--unicode-segmentation/src/lib.rs242
-rw-r--r--unicode-segmentation/src/sentence.rs373
-rw-r--r--unicode-segmentation/src/tables.rs2523
-rw-r--r--unicode-segmentation/src/test.rs197
-rw-r--r--unicode-segmentation/src/testdata.rs2122
-rw-r--r--unicode-segmentation/src/word.rs664
-rw-r--r--unicode-width/.gitignore3
-rw-r--r--unicode-width/.travis.yml28
-rw-r--r--unicode-width/COPYRIGHT7
-rw-r--r--unicode-width/Cargo.toml29
-rw-r--r--unicode-width/LICENSE-APACHE201
-rw-r--r--unicode-width/LICENSE-MIT25
-rw-r--r--unicode-width/README.md58
-rwxr-xr-xunicode-width/scripts/unicode.py321
-rw-r--r--unicode-width/src/lib.rs131
-rw-r--r--unicode-width/src/tables.rs284
-rw-r--r--unicode-width/src/tests.rs175
-rw-r--r--unicode-xid/.gitignore3
-rw-r--r--unicode-xid/.travis.yml25
-rw-r--r--unicode-xid/COPYRIGHT7
-rw-r--r--unicode-xid/Cargo.toml28
-rw-r--r--unicode-xid/LICENSE-APACHE201
-rw-r--r--unicode-xid/LICENSE-MIT25
-rw-r--r--unicode-xid/README.md44
-rwxr-xr-xunicode-xid/scripts/unicode.py187
-rw-r--r--unicode-xid/src/lib.rs87
-rw-r--r--unicode-xid/src/tables.rs451
-rw-r--r--unicode-xid/src/tests.rs111
604 files changed, 127025 insertions, 17 deletions
diff --git a/bitflags/.gitignore b/bitflags/.gitignore
new file mode 100644
index 0000000..fbd9642
--- /dev/null
+++ b/bitflags/.gitignore
@@ -0,0 +1,4 @@
+target
+Cargo.lock
+
+/.idea/
diff --git a/bitflags/.travis.yml b/bitflags/.travis.yml
new file mode 100644
index 0000000..9dd45c4
--- /dev/null
+++ b/bitflags/.travis.yml
@@ -0,0 +1,39 @@
+branches:
+ except:
+ - /.*(.tmp)$/
+
+language: rust
+matrix:
+ include:
+ # This version is tested to avoid unintentional bumping of the minimum supported Rust version
+ - rust: 1.20.0
+ env:
+ - LABEL="msrv"
+ script:
+ - cargo test
+ - rust: stable
+ env:
+ - LABEL="no-std"
+ script:
+ - rustup target add thumbv6m-none-eabi
+ - cargo build --features example_generated --target thumbv6m-none-eabi
+ - rust: nightly
+ env:
+ - LABEL="compiletest"
+ script:
+ - cargo test
+ - cargo test -p test_suite --features unstable
+ - rust: stable
+ - rust: stable
+ os: osx
+ - rust: beta
+ allow_failures:
+ - rust: nightly
+
+sudo: false
+script:
+ - cargo test --all
+
+notifications:
+ email:
+ on_success: never
diff --git a/bitflags/CHANGELOG.md b/bitflags/CHANGELOG.md
new file mode 100644
index 0000000..0d49101
--- /dev/null
+++ b/bitflags/CHANGELOG.md
@@ -0,0 +1,149 @@
+# 1.2.1
+
+- Remove extraneous `#[inline]` attributes ([#194])
+
+[#194]: https://github.com/bitflags/bitflags/pull/194
+
+# 1.2.0
+
+- Fix typo: {Lower, Upper}Exp - {Lower, Upper}Hex ([#183])
+
+- Add support for "unknown" bits ([#188])
+
+[#183]: https://github.com/rust-lang-nursery/bitflags/pull/183
+[#188]: https://github.com/rust-lang-nursery/bitflags/pull/188
+
+# 1.1.0
+
+This is a re-release of `1.0.5`, which was yanked due to a bug in the RLS.
+
+# 1.0.5
+
+- Use compiletest_rs flags supported by stable toolchain ([#171])
+
+- Put the user provided attributes first ([#173])
+
+- Make bitflags methods `const` on newer compilers ([#175])
+
+[#171]: https://github.com/rust-lang-nursery/bitflags/pull/171
+[#173]: https://github.com/rust-lang-nursery/bitflags/pull/173
+[#175]: https://github.com/rust-lang-nursery/bitflags/pull/175
+
+# 1.0.4
+
+- Support Rust 2018 style macro imports ([#165])
+
+ ```rust
+ use bitflags::bitflags;
+ ```
+
+[#165]: https://github.com/rust-lang-nursery/bitflags/pull/165
+
+# 1.0.3
+
+- Improve zero value flag handling and documentation ([#157])
+
+[#157]: https://github.com/rust-lang-nursery/bitflags/pull/157
+
+# 1.0.2
+
+- 30% improvement in compile time of bitflags crate ([#156])
+
+- Documentation improvements ([#153])
+
+- Implementation cleanup ([#149])
+
+[#156]: https://github.com/rust-lang-nursery/bitflags/pull/156
+[#153]: https://github.com/rust-lang-nursery/bitflags/pull/153
+[#149]: https://github.com/rust-lang-nursery/bitflags/pull/149
+
+# 1.0.1
+- Add support for `pub(restricted)` specifier on the bitflags struct ([#135])
+- Optimize performance of `all()` when called from a separate crate ([#136])
+
+[#135]: https://github.com/rust-lang-nursery/bitflags/pull/135
+[#136]: https://github.com/rust-lang-nursery/bitflags/pull/136
+
+# 1.0.0
+- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) ([#24])
+
+- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants
+
+- After being broken in 0.9, the `#[deprecated]` attribute is now supported again ([#112])
+
+- Other improvements to unit tests and documentation ([#106] and [#115])
+
+[#24]: https://github.com/rust-lang-nursery/bitflags/pull/24
+[#106]: https://github.com/rust-lang-nursery/bitflags/pull/106
+[#112]: https://github.com/rust-lang-nursery/bitflags/pull/112
+[#115]: https://github.com/rust-lang-nursery/bitflags/pull/115
+
+## How to update your code to use associated constants
+Assuming the following structure definition:
+```rust
+bitflags! {
+ struct Something: u8 {
+ const FOO = 0b01,
+ const BAR = 0b10
+ }
+}
+```
+In 0.9 and older you could do:
+```rust
+let x = FOO.bits | BAR.bits;
+```
+Now you must use:
+```rust
+let x = Something::FOO.bits | Something::BAR.bits;
+```
+
+# 0.9.1
+- Fix the implementation of `Formatting` traits when other formatting traits were present in scope ([#105])
+
+[#105]: https://github.com/rust-lang-nursery/bitflags/pull/105
+
+# 0.9.0
+- **[breaking change]** Use struct keyword instead of flags to define bitflag types ([#84])
+
+- **[breaking change]** Terminate const items with semicolons instead of commas ([#87])
+
+- Implement the `Hex`, `Octal`, and `Binary` formatting traits ([#86])
+
+- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing ([#85])
+
+- The `bitflags!` macro can now be used inside of a fn body, to define a type local to that function ([#74])
+
+[#74]: https://github.com/rust-lang-nursery/bitflags/pull/74
+[#84]: https://github.com/rust-lang-nursery/bitflags/pull/84
+[#85]: https://github.com/rust-lang-nursery/bitflags/pull/85
+[#86]: https://github.com/rust-lang-nursery/bitflags/pull/86
+[#87]: https://github.com/rust-lang-nursery/bitflags/pull/87
+
+# 0.8.2
+- Update feature flag used when building bitflags as a dependency of the Rust toolchain
+
+# 0.8.1
+- Allow bitflags to be used as a dependency of the Rust toolchain
+
+# 0.8.0
+- Add support for the experimental `i128` and `u128` integer types ([#57])
+- Add set method: `flags.set(SOME_FLAG, true)` or `flags.set(SOME_FLAG, false)` ([#55])
+ This may break code that defines its own set method
+
+[#55]: https://github.com/rust-lang-nursery/bitflags/pull/55
+[#57]: https://github.com/rust-lang-nursery/bitflags/pull/57
+
+# 0.7.1
+*(yanked)*
+
+# 0.7.0
+- Implement the Extend trait ([#49])
+- Allow definitions inside the `bitflags!` macro to refer to items imported from other modules ([#51])
+
+[#49]: https://github.com/rust-lang-nursery/bitflags/pull/49
+[#51]: https://github.com/rust-lang-nursery/bitflags/pull/51
+
+# 0.6.0
+- The `no_std` feature was removed as it is now the default
+- The `assignment_operators` feature was remove as it is now enabled by default
+- Some clippy suggestions have been applied
diff --git a/bitflags/CODE_OF_CONDUCT.md b/bitflags/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..f7add90
--- /dev/null
+++ b/bitflags/CODE_OF_CONDUCT.md
@@ -0,0 +1,73 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+education, socio-economic status, nationality, personal appearance, race,
+religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at coc@senaite.org. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org \ No newline at end of file
diff --git a/bitflags/Cargo.toml b/bitflags/Cargo.toml
new file mode 100644
index 0000000..afbe066
--- /dev/null
+++ b/bitflags/Cargo.toml
@@ -0,0 +1,37 @@
+[package]
+
+name = "bitflags"
+# NB: When modifying, also modify:
+# 1. html_root_url in lib.rs
+# 2. number in readme (for breaking changes)
+version = "1.2.1"
+authors = ["The Rust Project Developers"]
+license = "MIT/Apache-2.0"
+keywords = ["bit", "bitmask", "bitflags", "flags"]
+readme = "README.md"
+repository = "https://github.com/bitflags/bitflags"
+homepage = "https://github.com/bitflags/bitflags"
+documentation = "https://docs.rs/bitflags"
+categories = ["no-std"]
+description = """
+A macro to generate structures which behave like bitflags.
+"""
+exclude = [
+ ".travis.yml",
+ "appveyor.yml",
+ "bors.toml"
+]
+build = "build.rs"
+
+[badges]
+travis-ci = { repository = "bitflags/bitflags" }
+
+[features]
+default = []
+example_generated = []
+
+[package.metadata.docs.rs]
+features = [ "example_generated" ]
+
+[workspace]
+members = ["test_suite"]
diff --git a/bitflags/LICENSE-APACHE b/bitflags/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/bitflags/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/bitflags/LICENSE-MIT b/bitflags/LICENSE-MIT
new file mode 100644
index 0000000..39d4bdb
--- /dev/null
+++ b/bitflags/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+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/bitflags/README.md b/bitflags/README.md
new file mode 100644
index 0000000..df12934
--- /dev/null
+++ b/bitflags/README.md
@@ -0,0 +1,34 @@
+bitflags
+========
+
+[![Build Status](https://travis-ci.com/bitflags/bitflags.svg?branch=master)](https://travis-ci.com/bitflags/bitflags)
+[![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge)
+[![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags)
+[![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags)
+![Minimum rustc version](https://img.shields.io/badge/rustc-1.20+-yellow.svg)
+![License](https://img.shields.io/crates/l/bitflags.svg)
+
+A Rust macro to generate structures which behave like a set of bitflags
+
+- [Documentation](https://docs.rs/bitflags)
+- [Release notes](https://github.com/bitflags/bitflags/releases)
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+bitflags = "1.0"
+```
+
+and this to your crate root:
+
+```rust
+#[macro_use]
+extern crate bitflags;
+```
+
+## Rust Version Support
+
+The minimum supported Rust version is 1.20 due to use of associated constants.
diff --git a/bitflags/bors.toml b/bitflags/bors.toml
new file mode 100644
index 0000000..713ea9b
--- /dev/null
+++ b/bitflags/bors.toml
@@ -0,0 +1,3 @@
+status = [
+ "continuous-integration/travis-ci/push",
+]
diff --git a/bitflags/build.rs b/bitflags/build.rs
new file mode 100644
index 0000000..985757a
--- /dev/null
+++ b/bitflags/build.rs
@@ -0,0 +1,44 @@
+use std::env;
+use std::process::Command;
+use std::str::{self, FromStr};
+
+fn main(){
+ let minor = match rustc_minor_version() {
+ Some(minor) => minor,
+ None => return,
+ };
+
+ // const fn stabilized in Rust 1.31:
+ if minor >= 31 {
+ println!("cargo:rustc-cfg=bitflags_const_fn");
+ }
+}
+
+fn rustc_minor_version() -> Option<u32> {
+ let rustc = match env::var_os("RUSTC") {
+ Some(rustc) => rustc,
+ None => return None,
+ };
+
+ let output = match Command::new(rustc).arg("--version").output() {
+ Ok(output) => output,
+ Err(_) => return None,
+ };
+
+ let version = match str::from_utf8(&output.stdout) {
+ Ok(version) => version,
+ Err(_) => return None,
+ };
+
+ let mut pieces = version.split('.');
+ if pieces.next() != Some("rustc 1") {
+ return None;
+ }
+
+ let next = match pieces.next() {
+ Some(next) => next,
+ None => return None,
+ };
+
+ u32::from_str(next).ok()
+} \ No newline at end of file
diff --git a/bitflags/src/example_generated.rs b/bitflags/src/example_generated.rs
new file mode 100644
index 0000000..cf188d9
--- /dev/null
+++ b/bitflags/src/example_generated.rs
@@ -0,0 +1,14 @@
+//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS
+//! CRATE**.
+
+bitflags! {
+ /// This is the same `Flags` struct defined in the [crate level example](../index.html#example).
+ /// Note that this struct is just for documentation purposes only, it must not be used outside
+ /// this crate.
+ pub struct Flags: u32 {
+ const A = 0b00000001;
+ const B = 0b00000010;
+ const C = 0b00000100;
+ const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
+ }
+}
diff --git a/bitflags/src/lib.rs b/bitflags/src/lib.rs
new file mode 100644
index 0000000..3929b02
--- /dev/null
+++ b/bitflags/src/lib.rs
@@ -0,0 +1,1430 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags.
+//! It can be used for creating typesafe wrappers around C APIs.
+//!
+//! The `bitflags!` macro generates a `struct` that manages a set of flags. The
+//! flags should only be defined for integer types, otherwise unexpected type
+//! errors may occur at compile time.
+//!
+//! # Example
+//!
+//! ```
+//! #[macro_use]
+//! extern crate bitflags;
+//!
+//! bitflags! {
+//! struct Flags: u32 {
+//! const A = 0b00000001;
+//! const B = 0b00000010;
+//! const C = 0b00000100;
+//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
+//! }
+//! }
+//!
+//! fn main() {
+//! let e1 = Flags::A | Flags::C;
+//! let e2 = Flags::B | Flags::C;
+//! assert_eq!((e1 | e2), Flags::ABC); // union
+//! assert_eq!((e1 & e2), Flags::C); // intersection
+//! assert_eq!((e1 - e2), Flags::A); // set difference
+//! assert_eq!(!e2, Flags::A); // set complement
+//! }
+//! ```
+//!
+//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code
+//! generated by the above `bitflags!` expansion.
+//!
+//! The generated `struct`s can also be extended with type and trait
+//! implementations:
+//!
+//! ```
+//! #[macro_use]
+//! extern crate bitflags;
+//!
+//! use std::fmt;
+//!
+//! bitflags! {
+//! struct Flags: u32 {
+//! const A = 0b00000001;
+//! const B = 0b00000010;
+//! }
+//! }
+//!
+//! impl Flags {
+//! pub fn clear(&mut self) {
+//! self.bits = 0; // The `bits` field can be accessed from within the
+//! // same module where the `bitflags!` macro was invoked.
+//! }
+//! }
+//!
+//! impl fmt::Display for Flags {
+//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+//! write!(f, "hi!")
+//! }
+//! }
+//!
+//! fn main() {
+//! let mut flags = Flags::A | Flags::B;
+//! flags.clear();
+//! assert!(flags.is_empty());
+//! assert_eq!(format!("{}", flags), "hi!");
+//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B");
+//! assert_eq!(format!("{:?}", Flags::B), "B");
+//! }
+//! ```
+//!
+//! # Visibility
+//!
+//! The generated struct and its associated flag constants are not exported
+//! out of the current module by default. A definition can be exported out of
+//! the current module by adding `pub` before `flags`:
+//!
+//! ```
+//! #[macro_use]
+//! extern crate bitflags;
+//!
+//! mod example {
+//! bitflags! {
+//! pub struct Flags1: u32 {
+//! const A = 0b00000001;
+//! }
+//! }
+//! bitflags! {
+//! # pub
+//! struct Flags2: u32 {
+//! const B = 0b00000010;
+//! }
+//! }
+//! }
+//!
+//! fn main() {
+//! let flag1 = example::Flags1::A;
+//! let flag2 = example::Flags2::B; // error: const `B` is private
+//! }
+//! ```
+//!
+//! # Attributes
+//!
+//! Attributes can be attached to the generated `struct` by placing them
+//! before the `flags` keyword.
+//!
+//! # Trait implementations
+//!
+//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash`
+//! traits automatically derived for the `struct` using the `derive` attribute.
+//! Additional traits can be derived by providing an explicit `derive`
+//! attribute on `flags`.
+//!
+//! The `Extend` and `FromIterator` traits are implemented for the `struct`,
+//! too: `Extend` adds the union of the instances of the `struct` iterated over,
+//! while `FromIterator` calculates the union.
+//!
+//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` trait is also
+//! implemented by displaying the bits value of the internal struct.
+//!
+//! ## Operators
+//!
+//! The following operator traits are implemented for the generated `struct`:
+//!
+//! - `BitOr` and `BitOrAssign`: union
+//! - `BitAnd` and `BitAndAssign`: intersection
+//! - `BitXor` and `BitXorAssign`: toggle
+//! - `Sub` and `SubAssign`: set difference
+//! - `Not`: set complement
+//!
+//! # Methods
+//!
+//! The following methods are defined for the generated `struct`:
+//!
+//! - `empty`: an empty set of flags
+//! - `all`: the set of all defined flags
+//! - `bits`: the raw value of the flags currently stored
+//! - `from_bits`: convert from underlying bit representation, unless that
+//! representation contains bits that do not correspond to a
+//! defined flag
+//! - `from_bits_truncate`: convert from underlying bit representation, dropping
+//! any bits that do not correspond to defined flags
+//! - `from_bits_unchecked`: convert from underlying bit representation, keeping
+//! all bits (even those not corresponding to defined
+//! flags)
+//! - `is_empty`: `true` if no flags are currently stored
+//! - `is_all`: `true` if currently set flags exactly equal all defined flags
+//! - `intersects`: `true` if there are flags common to both `self` and `other`
+//! - `contains`: `true` all of the flags in `other` are contained within `self`
+//! - `insert`: inserts the specified flags in-place
+//! - `remove`: removes the specified flags in-place
+//! - `toggle`: the specified flags will be inserted if not present, and removed
+//! if they are.
+//! - `set`: inserts or removes the specified flags depending on the passed value
+//!
+//! ## Default
+//!
+//! The `Default` trait is not automatically implemented for the generated struct.
+//!
+//! If your default value is equal to `0` (which is the same value as calling `empty()`
+//! on the generated struct), you can simply derive `Default`:
+//!
+//! ```
+//! #[macro_use]
+//! extern crate bitflags;
+//!
+//! bitflags! {
+//! // Results in default value with bits: 0
+//! #[derive(Default)]
+//! struct Flags: u32 {
+//! const A = 0b00000001;
+//! const B = 0b00000010;
+//! const C = 0b00000100;
+//! }
+//! }
+//!
+//! fn main() {
+//! let derived_default: Flags = Default::default();
+//! assert_eq!(derived_default.bits(), 0);
+//! }
+//! ```
+//!
+//! If your default value is not equal to `0` you need to implement `Default` yourself:
+//!
+//! ```
+//! #[macro_use]
+//! extern crate bitflags;
+//!
+//! bitflags! {
+//! struct Flags: u32 {
+//! const A = 0b00000001;
+//! const B = 0b00000010;
+//! const C = 0b00000100;
+//! }
+//! }
+//!
+//! // explicit `Default` implementation
+//! impl Default for Flags {
+//! fn default() -> Flags {
+//! Flags::A | Flags::C
+//! }
+//! }
+//!
+//! fn main() {
+//! let implemented_default: Flags = Default::default();
+//! assert_eq!(implemented_default, (Flags::A | Flags::C));
+//! }
+//! ```
+//!
+//! # Zero Flags
+//!
+//! Flags with a value equal to zero will have some strange behavior that one should be aware of.
+//!
+//! ```
+//! #[macro_use]
+//! extern crate bitflags;
+//!
+//! bitflags! {
+//! struct Flags: u32 {
+//! const NONE = 0b00000000;
+//! const SOME = 0b00000001;
+//! }
+//! }
+//!
+//! fn main() {
+//! let empty = Flags::empty();
+//! let none = Flags::NONE;
+//! let some = Flags::SOME;
+//!
+//! // Zero flags are treated as always present
+//! assert!(empty.contains(Flags::NONE));
+//! assert!(none.contains(Flags::NONE));
+//! assert!(some.contains(Flags::NONE));
+//!
+//! // Zero flags will be ignored when testing for emptiness
+//! assert!(none.is_empty());
+//! }
+//! ```
+
+#![no_std]
+#![doc(html_root_url = "https://docs.rs/bitflags/1.2.1")]
+
+#[cfg(test)]
+#[macro_use]
+extern crate std;
+
+// Re-export libcore using an alias so that the macros can work without
+// requiring `extern crate core` downstream.
+#[doc(hidden)]
+pub extern crate core as _core;
+
+/// The macro used to generate the flag structure.
+///
+/// See the [crate level docs](../bitflags/index.html) for complete documentation.
+///
+/// # Example
+///
+/// ```
+/// #[macro_use]
+/// extern crate bitflags;
+///
+/// bitflags! {
+/// struct Flags: u32 {
+/// const A = 0b00000001;
+/// const B = 0b00000010;
+/// const C = 0b00000100;
+/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
+/// }
+/// }
+///
+/// fn main() {
+/// let e1 = Flags::A | Flags::C;
+/// let e2 = Flags::B | Flags::C;
+/// assert_eq!((e1 | e2), Flags::ABC); // union
+/// assert_eq!((e1 & e2), Flags::C); // intersection
+/// assert_eq!((e1 - e2), Flags::A); // set difference
+/// assert_eq!(!e2, Flags::A); // set complement
+/// }
+/// ```
+///
+/// The generated `struct`s can also be extended with type and trait
+/// implementations:
+///
+/// ```
+/// #[macro_use]
+/// extern crate bitflags;
+///
+/// use std::fmt;
+///
+/// bitflags! {
+/// struct Flags: u32 {
+/// const A = 0b00000001;
+/// const B = 0b00000010;
+/// }
+/// }
+///
+/// impl Flags {
+/// pub fn clear(&mut self) {
+/// self.bits = 0; // The `bits` field can be accessed from within the
+/// // same module where the `bitflags!` macro was invoked.
+/// }
+/// }
+///
+/// impl fmt::Display for Flags {
+/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+/// write!(f, "hi!")
+/// }
+/// }
+///
+/// fn main() {
+/// let mut flags = Flags::A | Flags::B;
+/// flags.clear();
+/// assert!(flags.is_empty());
+/// assert_eq!(format!("{}", flags), "hi!");
+/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B");
+/// assert_eq!(format!("{:?}", Flags::B), "B");
+/// }
+/// ```
+#[macro_export(local_inner_macros)]
+macro_rules! bitflags {
+ (
+ $(#[$outer:meta])*
+ pub struct $BitFlags:ident: $T:ty {
+ $(
+ $(#[$inner:ident $($args:tt)*])*
+ const $Flag:ident = $value:expr;
+ )+
+ }
+ ) => {
+ __bitflags! {
+ $(#[$outer])*
+ (pub) $BitFlags: $T {
+ $(
+ $(#[$inner $($args)*])*
+ $Flag = $value;
+ )+
+ }
+ }
+ };
+ (
+ $(#[$outer:meta])*
+ struct $BitFlags:ident: $T:ty {
+ $(
+ $(#[$inner:ident $($args:tt)*])*
+ const $Flag:ident = $value:expr;
+ )+
+ }
+ ) => {
+ __bitflags! {
+ $(#[$outer])*
+ () $BitFlags: $T {
+ $(
+ $(#[$inner $($args)*])*
+ $Flag = $value;
+ )+
+ }
+ }
+ };
+ (
+ $(#[$outer:meta])*
+ pub ($($vis:tt)+) struct $BitFlags:ident: $T:ty {
+ $(
+ $(#[$inner:ident $($args:tt)*])*
+ const $Flag:ident = $value:expr;
+ )+
+ }
+ ) => {
+ __bitflags! {
+ $(#[$outer])*
+ (pub ($($vis)+)) $BitFlags: $T {
+ $(
+ $(#[$inner $($args)*])*
+ $Flag = $value;
+ )+
+ }
+ }
+ };
+}
+
+#[macro_export(local_inner_macros)]
+#[doc(hidden)]
+macro_rules! __bitflags {
+ (
+ $(#[$outer:meta])*
+ ($($vis:tt)*) $BitFlags:ident: $T:ty {
+ $(
+ $(#[$inner:ident $($args:tt)*])*
+ $Flag:ident = $value:expr;
+ )+
+ }
+ ) => {
+ $(#[$outer])*
+ #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
+ $($vis)* struct $BitFlags {
+ bits: $T,
+ }
+
+ __impl_bitflags! {
+ $BitFlags: $T {
+ $(
+ $(#[$inner $($args)*])*
+ $Flag = $value;
+ )+
+ }
+ }
+ };
+}
+
+#[macro_export(local_inner_macros)]
+#[doc(hidden)]
+#[cfg(bitflags_const_fn)]
+macro_rules! __fn_bitflags {
+ (
+ $(# $attr_args:tt)*
+ const fn $($item:tt)*
+ ) => {
+ $(# $attr_args)*
+ const fn $($item)*
+ };
+ (
+ $(# $attr_args:tt)*
+ pub const fn $($item:tt)*
+ ) => {
+ $(# $attr_args)*
+ pub const fn $($item)*
+ };
+ (
+ $(# $attr_args:tt)*
+ pub const unsafe fn $($item:tt)*
+ ) => {
+ $(# $attr_args)*
+ pub const unsafe fn $($item)*
+ };
+}
+
+#[macro_export(local_inner_macros)]
+#[doc(hidden)]
+#[cfg(not(bitflags_const_fn))]
+macro_rules! __fn_bitflags {
+ (
+ $(# $attr_args:tt)*
+ const fn $($item:tt)*
+ ) => {
+ $(# $attr_args)*
+ fn $($item)*
+ };
+ (
+ $(# $attr_args:tt)*
+ pub const fn $($item:tt)*
+ ) => {
+ $(# $attr_args)*
+ pub fn $($item)*
+ };
+ (
+ $(# $attr_args:tt)*
+ pub const unsafe fn $($item:tt)*
+ ) => {
+ $(# $attr_args)*
+ pub unsafe fn $($item)*
+ };
+}
+
+#[macro_export(local_inner_macros)]
+#[doc(hidden)]
+macro_rules! __impl_bitflags {
+ (
+ $BitFlags:ident: $T:ty {
+ $(
+ $(#[$attr:ident $($args:tt)*])*
+ $Flag:ident = $value:expr;
+ )+
+ }
+ ) => {
+ impl $crate::_core::fmt::Debug for $BitFlags {
+ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
+ // This convoluted approach is to handle #[cfg]-based flag
+ // omission correctly. For example it needs to support:
+ //
+ // #[cfg(unix)] const A: Flag = /* ... */;
+ // #[cfg(windows)] const B: Flag = /* ... */;
+
+ // Unconditionally define a check for every flag, even disabled
+ // ones.
+ #[allow(non_snake_case)]
+ trait __BitFlags {
+ $(
+ #[inline]
+ fn $Flag(&self) -> bool { false }
+ )+
+ }
+
+ // Conditionally override the check for just those flags that
+ // are not #[cfg]ed away.
+ impl __BitFlags for $BitFlags {
+ $(
+ __impl_bitflags! {
+ #[allow(deprecated)]
+ #[inline]
+ $(? #[$attr $($args)*])*
+ fn $Flag(&self) -> bool {
+ if Self::$Flag.bits == 0 && self.bits != 0 {
+ false
+ } else {
+ self.bits & Self::$Flag.bits == Self::$Flag.bits
+ }
+ }
+ }
+ )+
+ }
+
+ let mut first = true;
+ $(
+ if <$BitFlags as __BitFlags>::$Flag(self) {
+ if !first {
+ f.write_str(" | ")?;
+ }
+ first = false;
+ f.write_str(__bitflags_stringify!($Flag))?;
+ }
+ )+
+ let extra_bits = self.bits & !$BitFlags::all().bits();
+ if extra_bits != 0 {
+ if !first {
+ f.write_str(" | ")?;
+ }
+ first = false;
+ f.write_str("0x")?;
+ $crate::_core::fmt::LowerHex::fmt(&extra_bits, f)?;
+ }
+ if first {
+ f.write_str("(empty)")?;
+ }
+ Ok(())
+ }
+ }
+ impl $crate::_core::fmt::Binary for $BitFlags {
+ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
+ $crate::_core::fmt::Binary::fmt(&self.bits, f)
+ }
+ }
+ impl $crate::_core::fmt::Octal for $BitFlags {
+ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
+ $crate::_core::fmt::Octal::fmt(&self.bits, f)
+ }
+ }
+ impl $crate::_core::fmt::LowerHex for $BitFlags {
+ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
+ $crate::_core::fmt::LowerHex::fmt(&self.bits, f)
+ }
+ }
+ impl $crate::_core::fmt::UpperHex for $BitFlags {
+ fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
+ $crate::_core::fmt::UpperHex::fmt(&self.bits, f)
+ }
+ }
+
+ #[allow(dead_code)]
+ impl $BitFlags {
+ $(
+ $(#[$attr $($args)*])*
+ pub const $Flag: $BitFlags = $BitFlags { bits: $value };
+ )+
+
+ __fn_bitflags! {
+ /// Returns an empty set of flags
+ #[inline]
+ pub const fn empty() -> $BitFlags {
+ $BitFlags { bits: 0 }
+ }
+ }
+
+ __fn_bitflags! {
+ /// Returns the set containing all flags.
+ #[inline]
+ pub const fn all() -> $BitFlags {
+ // See `Debug::fmt` for why this approach is taken.
+ #[allow(non_snake_case)]
+ trait __BitFlags {
+ $(
+ const $Flag: $T = 0;
+ )+
+ }
+ impl __BitFlags for $BitFlags {
+ $(
+ __impl_bitflags! {
+ #[allow(deprecated)]
+ $(? #[$attr $($args)*])*
+ const $Flag: $T = Self::$Flag.bits;
+ }
+ )+
+ }
+ $BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag)|+ }
+ }
+ }
+
+ __fn_bitflags! {
+ /// Returns the raw value of the flags currently stored.
+ #[inline]
+ pub const fn bits(&self) -> $T {
+ self.bits
+ }
+ }
+
+ /// Convert from underlying bit representation, unless that
+ /// representation contains bits that do not correspond to a flag.
+ #[inline]
+ pub fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> {
+ if (bits & !$BitFlags::all().bits()) == 0 {
+ $crate::_core::option::Option::Some($BitFlags { bits })
+ } else {
+ $crate::_core::option::Option::None
+ }
+ }
+
+ __fn_bitflags! {
+ /// Convert from underlying bit representation, dropping any bits
+ /// that do not correspond to flags.
+ #[inline]
+ pub const fn from_bits_truncate(bits: $T) -> $BitFlags {
+ $BitFlags { bits: bits & $BitFlags::all().bits }
+ }
+ }
+
+ __fn_bitflags! {
+ /// Convert from underlying bit representation, preserving all
+ /// bits (even those not corresponding to a defined flag).
+ #[inline]
+ pub const unsafe fn from_bits_unchecked(bits: $T) -> $BitFlags {
+ $BitFlags { bits }
+ }
+ }
+
+ __fn_bitflags! {
+ /// Returns `true` if no flags are currently stored.
+ #[inline]
+ pub const fn is_empty(&self) -> bool {
+ self.bits() == $BitFlags::empty().bits()
+ }
+ }
+
+ __fn_bitflags! {
+ /// Returns `true` if all flags are currently set.
+ #[inline]
+ pub const fn is_all(&self) -> bool {
+ self.bits == $BitFlags::all().bits
+ }
+ }
+
+ __fn_bitflags! {
+ /// Returns `true` if there are flags common to both `self` and `other`.
+ #[inline]
+ pub const fn intersects(&self, other: $BitFlags) -> bool {
+ !$BitFlags{ bits: self.bits & other.bits}.is_empty()
+ }
+ }
+
+ __fn_bitflags! {
+ /// Returns `true` all of the flags in `other` are contained within `self`.
+ #[inline]
+ pub const fn contains(&self, other: $BitFlags) -> bool {
+ (self.bits & other.bits) == other.bits
+ }
+ }
+
+ /// Inserts the specified flags in-place.
+ #[inline]
+ pub fn insert(&mut self, other: $BitFlags) {
+ self.bits |= other.bits;
+ }
+
+ /// Removes the specified flags in-place.
+ #[inline]
+ pub fn remove(&mut self, other: $BitFlags) {
+ self.bits &= !other.bits;
+ }
+
+ /// Toggles the specified flags in-place.
+ #[inline]
+ pub fn toggle(&mut self, other: $BitFlags) {
+ self.bits ^= other.bits;
+ }
+
+ /// Inserts or removes the specified flags depending on the passed value.
+ #[inline]
+ pub fn set(&mut self, other: $BitFlags, value: bool) {
+ if value {
+ self.insert(other);
+ } else {
+ self.remove(other);
+ }
+ }
+ }
+
+ impl $crate::_core::ops::BitOr for $BitFlags {
+ type Output = $BitFlags;
+
+ /// Returns the union of the two sets of flags.
+ #[inline]
+ fn bitor(self, other: $BitFlags) -> $BitFlags {
+ $BitFlags { bits: self.bits | other.bits }
+ }
+ }
+
+ impl $crate::_core::ops::BitOrAssign for $BitFlags {
+
+ /// Adds the set of flags.
+ #[inline]
+ fn bitor_assign(&mut self, other: $BitFlags) {
+ self.bits |= other.bits;
+ }
+ }
+
+ impl $crate::_core::ops::BitXor for $BitFlags {
+ type Output = $BitFlags;
+
+ /// Returns the left flags, but with all the right flags toggled.
+ #[inline]
+ fn bitxor(self, other: $BitFlags) -> $BitFlags {
+ $BitFlags { bits: self.bits ^ other.bits }
+ }
+ }
+
+ impl $crate::_core::ops::BitXorAssign for $BitFlags {
+
+ /// Toggles the set of flags.
+ #[inline]
+ fn bitxor_assign(&mut self, other: $BitFlags) {
+ self.bits ^= other.bits;
+ }
+ }
+
+ impl $crate::_core::ops::BitAnd for $BitFlags {
+ type Output = $BitFlags;
+
+ /// Returns the intersection between the two sets of flags.
+ #[inline]
+ fn bitand(self, other: $BitFlags) -> $BitFlags {
+ $BitFlags { bits: self.bits & other.bits }
+ }
+ }
+
+ impl $crate::_core::ops::BitAndAssign for $BitFlags {
+
+ /// Disables all flags disabled in the set.
+ #[inline]
+ fn bitand_assign(&mut self, other: $BitFlags) {
+ self.bits &= other.bits;
+ }
+ }
+
+ impl $crate::_core::ops::Sub for $BitFlags {
+ type Output = $BitFlags;
+
+ /// Returns the set difference of the two sets of flags.
+ #[inline]
+ fn sub(self, other: $BitFlags) -> $BitFlags {
+ $BitFlags { bits: self.bits & !other.bits }
+ }
+ }
+
+ impl $crate::_core::ops::SubAssign for $BitFlags {
+
+ /// Disables all flags enabled in the set.
+ #[inline]
+ fn sub_assign(&mut self, other: $BitFlags) {
+ self.bits &= !other.bits;
+ }
+ }
+
+ impl $crate::_core::ops::Not for $BitFlags {
+ type Output = $BitFlags;
+
+ /// Returns the complement of this set of flags.
+ #[inline]
+ fn not(self) -> $BitFlags {
+ $BitFlags { bits: !self.bits } & $BitFlags::all()
+ }
+ }
+
+ impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags {
+ fn extend<T: $crate::_core::iter::IntoIterator<Item=$BitFlags>>(&mut self, iterator: T) {
+ for item in iterator {
+ self.insert(item)
+ }
+ }
+ }
+
+ impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags {
+ fn from_iter<T: $crate::_core::iter::IntoIterator<Item=$BitFlags>>(iterator: T) -> $BitFlags {
+ let mut result = Self::empty();
+ result.extend(iterator);
+ result
+ }
+ }
+ };
+
+ // Every attribute that the user writes on a const is applied to the
+ // corresponding const that we generate, but within the implementation of
+ // Debug and all() we want to ignore everything but #[cfg] attributes. In
+ // particular, including a #[deprecated] attribute on those items would fail
+ // to compile.
+ // https://github.com/bitflags/bitflags/issues/109
+ //
+ // Input:
+ //
+ // ? #[cfg(feature = "advanced")]
+ // ? #[deprecated(note = "Use somthing else.")]
+ // ? #[doc = r"High quality documentation."]
+ // fn f() -> i32 { /* ... */ }
+ //
+ // Output:
+ //
+ // #[cfg(feature = "advanced")]
+ // fn f() -> i32 { /* ... */ }
+ (
+ $(#[$filtered:meta])*
+ ? #[cfg $($cfgargs:tt)*]
+ $(? #[$rest:ident $($restargs:tt)*])*
+ fn $($item:tt)*
+ ) => {
+ __impl_bitflags! {
+ $(#[$filtered])*
+ #[cfg $($cfgargs)*]
+ $(? #[$rest $($restargs)*])*
+ fn $($item)*
+ }
+ };
+ (
+ $(#[$filtered:meta])*
+ // $next != `cfg`
+ ? #[$next:ident $($nextargs:tt)*]
+ $(? #[$rest:ident $($restargs:tt)*])*
+ fn $($item:tt)*
+ ) => {
+ __impl_bitflags! {
+ $(#[$filtered])*
+ // $next filtered out
+ $(? #[$rest $($restargs)*])*
+ fn $($item)*
+ }
+ };
+ (
+ $(#[$filtered:meta])*
+ fn $($item:tt)*
+ ) => {
+ $(#[$filtered])*
+ fn $($item)*
+ };
+
+ // Every attribute that the user writes on a const is applied to the
+ // corresponding const that we generate, but within the implementation of
+ // Debug and all() we want to ignore everything but #[cfg] attributes. In
+ // particular, including a #[deprecated] attribute on those items would fail
+ // to compile.
+ // https://github.com/bitflags/bitflags/issues/109
+ //
+ // const version
+ //
+ // Input:
+ //
+ // ? #[cfg(feature = "advanced")]
+ // ? #[deprecated(note = "Use somthing else.")]
+ // ? #[doc = r"High quality documentation."]
+ // const f: i32 { /* ... */ }
+ //
+ // Output:
+ //
+ // #[cfg(feature = "advanced")]
+ // const f: i32 { /* ... */ }
+ (
+ $(#[$filtered:meta])*
+ ? #[cfg $($cfgargs:tt)*]
+ $(? #[$rest:ident $($restargs:tt)*])*
+ const $($item:tt)*
+ ) => {
+ __impl_bitflags! {
+ $(#[$filtered])*
+ #[cfg $($cfgargs)*]
+ $(? #[$rest $($restargs)*])*
+ const $($item)*
+ }
+ };
+ (
+ $(#[$filtered:meta])*
+ // $next != `cfg`
+ ? #[$next:ident $($nextargs:tt)*]
+ $(? #[$rest:ident $($restargs:tt)*])*
+ const $($item:tt)*
+ ) => {
+ __impl_bitflags! {
+ $(#[$filtered])*
+ // $next filtered out
+ $(? #[$rest $($restargs)*])*
+ const $($item)*
+ }
+ };
+ (
+ $(#[$filtered:meta])*
+ const $($item:tt)*
+ ) => {
+ $(#[$filtered])*
+ const $($item)*
+ };
+}
+
+// Same as std::stringify but callable from __impl_bitflags, which needs to use
+// local_inner_macros so can only directly call macros from this crate.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! __bitflags_stringify {
+ ($s:ident) => {
+ stringify!($s)
+ };
+}
+
+#[cfg(feature = "example_generated")]
+pub mod example_generated;
+
+#[cfg(test)]
+mod tests {
+ use std::collections::hash_map::DefaultHasher;
+ use std::hash::{Hash, Hasher};
+
+ bitflags! {
+ #[doc = "> The first principle is that you must not fool yourself — and"]
+ #[doc = "> you are the easiest person to fool."]
+ #[doc = "> "]
+ #[doc = "> - Richard Feynman"]
+ struct Flags: u32 {
+ const A = 0b00000001;
+ #[doc = "<pcwalton> macros are way better at generating code than trans is"]
+ const B = 0b00000010;
+ const C = 0b00000100;
+ #[doc = "* cmr bed"]
+ #[doc = "* strcat table"]
+ #[doc = "<strcat> wait what?"]
+ const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
+ }
+ }
+
+ bitflags! {
+ struct _CfgFlags: u32 {
+ #[cfg(unix)]
+ const _CFG_A = 0b01;
+ #[cfg(windows)]
+ const _CFG_B = 0b01;
+ #[cfg(unix)]
+ const _CFG_C = Self::_CFG_A.bits | 0b10;
+ }
+ }
+
+ bitflags! {
+ struct AnotherSetOfFlags: i8 {
+ const ANOTHER_FLAG = -1_i8;
+ }
+ }
+
+ bitflags! {
+ struct LongFlags: u32 {
+ const LONG_A = 0b1111111111111111;
+ }
+ }
+
+ #[test]
+ fn test_bits() {
+ assert_eq!(Flags::empty().bits(), 0b00000000);
+ assert_eq!(Flags::A.bits(), 0b00000001);
+ assert_eq!(Flags::ABC.bits(), 0b00000111);
+
+ assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00);
+ assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8);
+ }
+
+ #[test]
+ fn test_from_bits() {
+ assert_eq!(Flags::from_bits(0), Some(Flags::empty()));
+ assert_eq!(Flags::from_bits(0b1), Some(Flags::A));
+ assert_eq!(Flags::from_bits(0b10), Some(Flags::B));
+ assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B));
+ assert_eq!(Flags::from_bits(0b1000), None);
+
+ assert_eq!(
+ AnotherSetOfFlags::from_bits(!0_i8),
+ Some(AnotherSetOfFlags::ANOTHER_FLAG)
+ );
+ }
+
+ #[test]
+ fn test_from_bits_truncate() {
+ assert_eq!(Flags::from_bits_truncate(0), Flags::empty());
+ assert_eq!(Flags::from_bits_truncate(0b1), Flags::A);
+ assert_eq!(Flags::from_bits_truncate(0b10), Flags::B);
+ assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B));
+ assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty());
+ assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A);
+
+ assert_eq!(
+ AnotherSetOfFlags::from_bits_truncate(0_i8),
+ AnotherSetOfFlags::empty()
+ );
+ }
+
+ #[test]
+ fn test_from_bits_unchecked() {
+ let extra = unsafe { Flags::from_bits_unchecked(0b1000) };
+ assert_eq!(unsafe { Flags::from_bits_unchecked(0) }, Flags::empty());
+ assert_eq!(unsafe { Flags::from_bits_unchecked(0b1) }, Flags::A);
+ assert_eq!(unsafe { Flags::from_bits_unchecked(0b10) }, Flags::B);
+ assert_eq!(unsafe { Flags::from_bits_unchecked(0b11) }, (Flags::A | Flags::B));
+ assert_eq!(unsafe { Flags::from_bits_unchecked(0b1000) }, (extra | Flags::empty()));
+ assert_eq!(unsafe { Flags::from_bits_unchecked(0b1001) }, (extra | Flags::A));
+ }
+
+ #[test]
+ fn test_is_empty() {
+ assert!(Flags::empty().is_empty());
+ assert!(!Flags::A.is_empty());
+ assert!(!Flags::ABC.is_empty());
+
+ assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty());
+ }
+
+ #[test]
+ fn test_is_all() {
+ assert!(Flags::all().is_all());
+ assert!(!Flags::A.is_all());
+ assert!(Flags::ABC.is_all());
+
+ assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all());
+ }
+
+ #[test]
+ fn test_two_empties_do_not_intersect() {
+ let e1 = Flags::empty();
+ let e2 = Flags::empty();
+ assert!(!e1.intersects(e2));
+
+ assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG));
+ }
+
+ #[test]
+ fn test_empty_does_not_intersect_with_full() {
+ let e1 = Flags::empty();
+ let e2 = Flags::ABC;
+ assert!(!e1.intersects(e2));
+ }
+
+ #[test]
+ fn test_disjoint_intersects() {
+ let e1 = Flags::A;
+ let e2 = Flags::B;
+ assert!(!e1.intersects(e2));
+ }
+
+ #[test]
+ fn test_overlapping_intersects() {
+ let e1 = Flags::A;
+ let e2 = Flags::A | Flags::B;
+ assert!(e1.intersects(e2));
+ }
+
+ #[test]
+ fn test_contains() {
+ let e1 = Flags::A;
+ let e2 = Flags::A | Flags::B;
+ assert!(!e1.contains(e2));
+ assert!(e2.contains(e1));
+ assert!(Flags::ABC.contains(e2));
+
+ assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG));
+ }
+
+ #[test]
+ fn test_insert() {
+ let mut e1 = Flags::A;
+ let e2 = Flags::A | Flags::B;
+ e1.insert(e2);
+ assert_eq!(e1, e2);
+
+ let mut e3 = AnotherSetOfFlags::empty();
+ e3.insert(AnotherSetOfFlags::ANOTHER_FLAG);
+ assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG);
+ }
+
+ #[test]
+ fn test_remove() {
+ let mut e1 = Flags::A | Flags::B;
+ let e2 = Flags::A | Flags::C;
+ e1.remove(e2);
+ assert_eq!(e1, Flags::B);
+
+ let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG;
+ e3.remove(AnotherSetOfFlags::ANOTHER_FLAG);
+ assert_eq!(e3, AnotherSetOfFlags::empty());
+ }
+
+ #[test]
+ fn test_operators() {
+ let e1 = Flags::A | Flags::C;
+ let e2 = Flags::B | Flags::C;
+ assert_eq!((e1 | e2), Flags::ABC); // union
+ assert_eq!((e1 & e2), Flags::C); // intersection
+ assert_eq!((e1 - e2), Flags::A); // set difference
+ assert_eq!(!e2, Flags::A); // set complement
+ assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle
+ let mut e3 = e1;
+ e3.toggle(e2);
+ assert_eq!(e3, Flags::A | Flags::B);
+
+ let mut m4 = AnotherSetOfFlags::empty();
+ m4.toggle(AnotherSetOfFlags::empty());
+ assert_eq!(m4, AnotherSetOfFlags::empty());
+ }
+
+ #[test]
+ fn test_operators_unchecked() {
+ let extra = unsafe { Flags::from_bits_unchecked(0b1000) };
+ let e1 = Flags::A | Flags::C | extra;
+ let e2 = Flags::B | Flags::C;
+ assert_eq!((e1 | e2), (Flags::ABC | extra)); // union
+ assert_eq!((e1 & e2), Flags::C); // intersection
+ assert_eq!((e1 - e2), (Flags::A | extra)); // set difference
+ assert_eq!(!e2, Flags::A); // set complement
+ assert_eq!(!e1, Flags::B); // set complement
+ assert_eq!(e1 ^ e2, Flags::A | Flags::B | extra); // toggle
+ let mut e3 = e1;
+ e3.toggle(e2);
+ assert_eq!(e3, Flags::A | Flags::B | extra);
+ }
+
+ #[test]
+ fn test_set() {
+ let mut e1 = Flags::A | Flags::C;
+ e1.set(Flags::B, true);
+ e1.set(Flags::C, false);
+
+ assert_eq!(e1, Flags::A | Flags::B);
+ }
+
+ #[test]
+ fn test_assignment_operators() {
+ let mut m1 = Flags::empty();
+ let e1 = Flags::A | Flags::C;
+ // union
+ m1 |= Flags::A;
+ assert_eq!(m1, Flags::A);
+ // intersection
+ m1 &= e1;
+ assert_eq!(m1, Flags::A);
+ // set difference
+ m1 -= m1;
+ assert_eq!(m1, Flags::empty());
+ // toggle
+ m1 ^= e1;
+ assert_eq!(m1, e1);
+ }
+
+
+ #[cfg(bitflags_const_fn)]
+ #[test]
+ fn test_const_fn() {
+ const _M1: Flags = Flags::empty();
+
+ const M2: Flags = Flags::A;
+ assert_eq!(M2, Flags::A);
+
+ const M3: Flags = Flags::C;
+ assert_eq!(M3, Flags::C);
+ }
+
+ #[test]
+ fn test_extend() {
+ let mut flags;
+
+ flags = Flags::empty();
+ flags.extend([].iter().cloned());
+ assert_eq!(flags, Flags::empty());
+
+ flags = Flags::empty();
+ flags.extend([Flags::A, Flags::B].iter().cloned());
+ assert_eq!(flags, Flags::A | Flags::B);
+
+ flags = Flags::A;
+ flags.extend([Flags::A, Flags::B].iter().cloned());
+ assert_eq!(flags, Flags::A | Flags::B);
+
+ flags = Flags::B;
+ flags.extend([Flags::A, Flags::ABC].iter().cloned());
+ assert_eq!(flags, Flags::ABC);
+ }
+
+ #[test]
+ fn test_from_iterator() {
+ assert_eq!([].iter().cloned().collect::<Flags>(), Flags::empty());
+ assert_eq!(
+ [Flags::A, Flags::B].iter().cloned().collect::<Flags>(),
+ Flags::A | Flags::B
+ );
+ assert_eq!(
+ [Flags::A, Flags::ABC].iter().cloned().collect::<Flags>(),
+ Flags::ABC
+ );
+ }
+
+ #[test]
+ fn test_lt() {
+ let mut a = Flags::empty();
+ let mut b = Flags::empty();
+
+ assert!(!(a < b) && !(b < a));
+ b = Flags::B;
+ assert!(a < b);
+ a = Flags::C;
+ assert!(!(a < b) && b < a);
+ b = Flags::C | Flags::B;
+ assert!(a < b);
+ }
+
+ #[test]
+ fn test_ord() {
+ let mut a = Flags::empty();
+ let mut b = Flags::empty();
+
+ assert!(a <= b && a >= b);
+ a = Flags::A;
+ assert!(a > b && a >= b);
+ assert!(b < a && b <= a);
+ b = Flags::B;
+ assert!(b > a && b >= a);
+ assert!(a < b && a <= b);
+ }
+
+ fn hash<T: Hash>(t: &T) -> u64 {
+ let mut s = DefaultHasher::new();
+ t.hash(&mut s);
+ s.finish()
+ }
+
+ #[test]
+ fn test_hash() {
+ let mut x = Flags::empty();
+ let mut y = Flags::empty();
+ assert_eq!(hash(&x), hash(&y));
+ x = Flags::all();
+ y = Flags::ABC;
+ assert_eq!(hash(&x), hash(&y));
+ }
+
+ #[test]
+ fn test_debug() {
+ assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B");
+ assert_eq!(format!("{:?}", Flags::empty()), "(empty)");
+ assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC");
+ let extra = unsafe { Flags::from_bits_unchecked(0xb8) };
+ assert_eq!(format!("{:?}", extra), "0xb8");
+ assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8");
+ assert_eq!(format!("{:?}", Flags::ABC | extra), "A | B | C | ABC | 0xb8");
+ }
+
+ #[test]
+ fn test_binary() {
+ assert_eq!(format!("{:b}", Flags::ABC), "111");
+ assert_eq!(format!("{:#b}", Flags::ABC), "0b111");
+ let extra = unsafe { Flags::from_bits_unchecked(0b1010000) };
+ assert_eq!(format!("{:b}", Flags::ABC | extra), "1010111");
+ assert_eq!(format!("{:#b}", Flags::ABC | extra), "0b1010111");
+ }
+
+ #[test]
+ fn test_octal() {
+ assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777");
+ assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777");
+ let extra = unsafe { LongFlags::from_bits_unchecked(0o5000000) };
+ assert_eq!(format!("{:o}", LongFlags::LONG_A | extra), "5177777");
+ assert_eq!(format!("{:#o}", LongFlags::LONG_A | extra), "0o5177777");
+ }
+
+ #[test]
+ fn test_lowerhex() {
+ assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff");
+ assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff");
+ let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) };
+ assert_eq!(format!("{:x}", LongFlags::LONG_A | extra), "e0ffff");
+ assert_eq!(format!("{:#x}", LongFlags::LONG_A | extra), "0xe0ffff");
+ }
+
+ #[test]
+ fn test_upperhex() {
+ assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF");
+ assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF");
+ let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) };
+ assert_eq!(format!("{:X}", LongFlags::LONG_A | extra), "E0FFFF");
+ assert_eq!(format!("{:#X}", LongFlags::LONG_A | extra), "0xE0FFFF");
+ }
+
+ mod submodule {
+ bitflags! {
+ pub struct PublicFlags: i8 {
+ const X = 0;
+ }
+ }
+ bitflags! {
+ struct PrivateFlags: i8 {
+ const Y = 0;
+ }
+ }
+
+ #[test]
+ fn test_private() {
+ let _ = PrivateFlags::Y;
+ }
+ }
+
+ #[test]
+ fn test_public() {
+ let _ = submodule::PublicFlags::X;
+ }
+
+ mod t1 {
+ mod foo {
+ pub type Bar = i32;
+ }
+
+ bitflags! {
+ /// baz
+ struct Flags: foo::Bar {
+ const A = 0b00000001;
+ #[cfg(foo)]
+ const B = 0b00000010;
+ #[cfg(foo)]
+ const C = 0b00000010;
+ }
+ }
+ }
+
+ #[test]
+ fn test_in_function() {
+ bitflags! {
+ struct Flags: u8 {
+ const A = 1;
+ #[cfg(any())] // false
+ const B = 2;
+ }
+ }
+ assert_eq!(Flags::all(), Flags::A);
+ assert_eq!(format!("{:?}", Flags::A), "A");
+ }
+
+ #[test]
+ fn test_deprecated() {
+ bitflags! {
+ pub struct TestFlags: u32 {
+ #[deprecated(note = "Use something else.")]
+ const ONE = 1;
+ }
+ }
+ }
+
+ #[test]
+ fn test_pub_crate() {
+ mod module {
+ bitflags! {
+ pub (crate) struct Test: u8 {
+ const FOO = 1;
+ }
+ }
+ }
+
+ assert_eq!(module::Test::FOO.bits(), 1);
+ }
+
+ #[test]
+ fn test_pub_in_module() {
+ mod module {
+ mod submodule {
+ bitflags! {
+ // `pub (in super)` means only the module `module` will
+ // be able to access this.
+ pub (in super) struct Test: u8 {
+ const FOO = 1;
+ }
+ }
+ }
+
+ mod test {
+ // Note: due to `pub (in super)`,
+ // this cannot be accessed directly by the testing code.
+ pub(super) fn value() -> u8 {
+ super::submodule::Test::FOO.bits()
+ }
+ }
+
+ pub fn value() -> u8 {
+ test::value()
+ }
+ }
+
+ assert_eq!(module::value(), 1)
+ }
+
+ #[test]
+ fn test_zero_value_flags() {
+ bitflags! {
+ struct Flags: u32 {
+ const NONE = 0b0;
+ const SOME = 0b1;
+ }
+ }
+
+ assert!(Flags::empty().contains(Flags::NONE));
+ assert!(Flags::SOME.contains(Flags::NONE));
+ assert!(Flags::NONE.is_empty());
+
+ assert_eq!(format!("{:?}", Flags::empty()), "NONE");
+ assert_eq!(format!("{:?}", Flags::SOME), "SOME");
+ }
+}
diff --git a/bitflags/test_suite/Cargo.toml b/bitflags/test_suite/Cargo.toml
new file mode 100644
index 0000000..2a02d80
--- /dev/null
+++ b/bitflags/test_suite/Cargo.toml
@@ -0,0 +1,13 @@
+[project]
+name = "test_suite"
+version = "0.0.0"
+
+[features]
+unstable = ["compiletest_rs"]
+
+[dependencies]
+bitflags = { path = "../" }
+compiletest_rs = { version = "0.3.18", optional = true, features=["stable"] }
+serde = "1.0"
+serde_derive = "1.0"
+serde_json = "1.0"
diff --git a/bitflags/test_suite/tests/compile-fail/private_flags.rs b/bitflags/test_suite/tests/compile-fail/private_flags.rs
new file mode 100644
index 0000000..d31c28d
--- /dev/null
+++ b/bitflags/test_suite/tests/compile-fail/private_flags.rs
@@ -0,0 +1,20 @@
+#[macro_use]
+extern crate bitflags;
+
+mod example {
+ bitflags! {
+ pub struct Flags1: u32 {
+ const FLAG_A = 0b00000001;
+ }
+ }
+ bitflags! {
+ struct Flags2: u32 {
+ const FLAG_B = 0b00000010;
+ }
+ }
+}
+
+fn main() {
+ let flag1 = example::Flags1::FLAG_A;
+ let flag2 = example::Flags2::FLAG_B; //~ ERROR struct `Flags2` is private
+}
diff --git a/bitflags/test_suite/tests/compiletest.rs b/bitflags/test_suite/tests/compiletest.rs
new file mode 100644
index 0000000..2beeae0
--- /dev/null
+++ b/bitflags/test_suite/tests/compiletest.rs
@@ -0,0 +1,33 @@
+#![cfg(feature = "unstable")]
+
+extern crate compiletest_rs as compiletest;
+
+use std::fs;
+use std::result::Result;
+
+use compiletest::common::Mode;
+
+fn run_mode(mode: Mode) {
+ let config = compiletest::Config {
+ mode: mode,
+ src_base: format!("tests/{}", mode).into(),
+ target_rustcflags: fs::read_dir("../target/debug/deps")
+ .unwrap()
+ .map(Result::unwrap)
+ .filter(|entry| {
+ let file_name = entry.file_name();
+ let file_name = file_name.to_string_lossy();
+ file_name.starts_with("libbitflags-") && file_name.ends_with(".rlib")
+ })
+ .max_by_key(|entry| entry.metadata().unwrap().modified().unwrap())
+ .map(|entry| format!("--extern bitflags={}", entry.path().to_string_lossy())),
+ ..Default::default()
+ };
+
+ compiletest::run_tests(&config);
+}
+
+#[test]
+fn compile_test() {
+ run_mode(Mode::CompileFail);
+}
diff --git a/bitflags/test_suite/tests/conflicting_trait_impls.rs b/bitflags/test_suite/tests/conflicting_trait_impls.rs
new file mode 100644
index 0000000..eb7a325
--- /dev/null
+++ b/bitflags/test_suite/tests/conflicting_trait_impls.rs
@@ -0,0 +1,17 @@
+#![no_std]
+
+#[macro_use]
+extern crate bitflags;
+
+#[allow(unused_imports)]
+use core::fmt::Display;
+
+bitflags! {
+ /// baz
+ struct Flags: u32 {
+ const A = 0b00000001;
+ }
+}
+
+#[test]
+fn main() {}
diff --git a/bitflags/test_suite/tests/external.rs b/bitflags/test_suite/tests/external.rs
new file mode 100644
index 0000000..4c88387
--- /dev/null
+++ b/bitflags/test_suite/tests/external.rs
@@ -0,0 +1,19 @@
+#[macro_use]
+extern crate bitflags;
+
+bitflags! {
+ /// baz
+ struct Flags: u32 {
+ const A = 0b00000001;
+ #[doc = "bar"]
+ const B = 0b00000010;
+ const C = 0b00000100;
+ #[doc = "foo"]
+ const ABC = Flags::A.bits | Flags::B.bits | Flags::C.bits;
+ }
+}
+
+#[test]
+fn smoke() {
+ assert_eq!(Flags::ABC, Flags::A | Flags::B | Flags::C);
+}
diff --git a/bitflags/test_suite/tests/external_no_std.rs b/bitflags/test_suite/tests/external_no_std.rs
new file mode 100644
index 0000000..31f87e4
--- /dev/null
+++ b/bitflags/test_suite/tests/external_no_std.rs
@@ -0,0 +1,21 @@
+#![no_std]
+
+#[macro_use]
+extern crate bitflags;
+
+bitflags! {
+ /// baz
+ struct Flags: u32 {
+ const A = 0b00000001;
+ #[doc = "bar"]
+ const B = 0b00000010;
+ const C = 0b00000100;
+ #[doc = "foo"]
+ const ABC = Flags::A.bits | Flags::B.bits | Flags::C.bits;
+ }
+}
+
+#[test]
+fn smoke() {
+ assert_eq!(Flags::ABC, Flags::A | Flags::B | Flags::C);
+}
diff --git a/bitflags/test_suite/tests/i128_bitflags.rs b/bitflags/test_suite/tests/i128_bitflags.rs
new file mode 100644
index 0000000..1b6f7c5
--- /dev/null
+++ b/bitflags/test_suite/tests/i128_bitflags.rs
@@ -0,0 +1,30 @@
+#![cfg(feature = "unstable")]
+
+#[macro_use]
+extern crate bitflags;
+
+bitflags! {
+ /// baz
+ struct Flags128: u128 {
+ const A = 0x0000_0000_0000_0000_0000_0000_0000_0001;
+ const B = 0x0000_0000_0000_1000_0000_0000_0000_0000;
+ const C = 0x8000_0000_0000_0000_0000_0000_0000_0000;
+ const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
+ }
+}
+
+#[test]
+fn test_i128_bitflags() {
+ assert_eq!(Flags128::ABC, Flags128::A | Flags128::B | Flags128::C);
+ assert_eq!(Flags128::A.bits, 0x0000_0000_0000_0000_0000_0000_0000_0001);
+ assert_eq!(Flags128::B.bits, 0x0000_0000_0000_1000_0000_0000_0000_0000);
+ assert_eq!(Flags128::C.bits, 0x8000_0000_0000_0000_0000_0000_0000_0000);
+ assert_eq!(
+ Flags128::ABC.bits,
+ 0x8000_0000_0000_1000_0000_0000_0000_0001
+ );
+ assert_eq!(format!("{:?}", Flags128::A), "A");
+ assert_eq!(format!("{:?}", Flags128::B), "B");
+ assert_eq!(format!("{:?}", Flags128::C), "C");
+ assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C | ABC");
+}
diff --git a/bitflags/test_suite/tests/serde.rs b/bitflags/test_suite/tests/serde.rs
new file mode 100644
index 0000000..0424af5
--- /dev/null
+++ b/bitflags/test_suite/tests/serde.rs
@@ -0,0 +1,35 @@
+#[macro_use]
+extern crate bitflags;
+
+#[macro_use]
+extern crate serde_derive;
+extern crate serde;
+extern crate serde_json;
+
+bitflags! {
+ #[derive(Serialize, Deserialize)]
+ struct Flags: u32 {
+ const A = 1;
+ const B = 2;
+ const C = 4;
+ const D = 8;
+ }
+}
+
+#[test]
+fn serialize() {
+ let flags = Flags::A | Flags::B;
+
+ let serialized = serde_json::to_string(&flags).unwrap();
+
+ assert_eq!(serialized, r#"{"bits":3}"#);
+}
+
+#[test]
+fn deserialize() {
+ let deserialized: Flags = serde_json::from_str(r#"{"bits":12}"#).unwrap();
+
+ let expected = Flags::C | Flags::D;
+
+ assert_eq!(deserialized.bits, expected.bits);
+}
diff --git a/clap/.appveyor.yml b/clap/.appveyor.yml
new file mode 100644
index 0000000..247a550
--- /dev/null
+++ b/clap/.appveyor.yml
@@ -0,0 +1,17 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+ - TARGET: i686-pc-windows-msvc
+ - TARGET: x86_64-pc-windows-gnu
+ - TARGET: i686-pc-windows-gnu
+ RUST_BACKTRACE: full
+install:
+ - curl -sSf -o rustup-init.exe https://win.rustup.rs/
+ - rustup-init.exe -y --default-host %TARGET%
+ - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+ - rustc -vV
+ - cargo -vV
+build: false
+test_script:
+ - cargo build --verbose --features yaml
+ - cargo test --verbose --features yaml
diff --git a/clap/.clog.toml b/clap/.clog.toml
new file mode 100644
index 0000000..301dd92
--- /dev/null
+++ b/clap/.clog.toml
@@ -0,0 +1,14 @@
+[clog]
+repository = "https://github.com/kbknapp/clap-rs"
+outfile = "CHANGELOG.md"
+from-latest-tag = true
+
+[sections]
+Performance = ["perf"]
+Improvements = ["impr", "im", "imp"]
+Documentation = ["docs"]
+Deprecations = ["depr"]
+Examples = ["examples"]
+"New Settings" = ["setting", "settings"]
+"API Additions" = ["add", "api"]
+"New Sponsor" = ["sponsor"]
diff --git a/clap/.github/CONTRIBUTING.md b/clap/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..2c6f752
--- /dev/null
+++ b/clap/.github/CONTRIBUTING.md
@@ -0,0 +1,115 @@
+# How to Contribute
+
+Contributions are always welcome! And there is a multitude of ways in which you can help depending on what you like to do, or are good at. Anything from documentation, code cleanup, issue completion, new features, you name it, even filing issues is contributing and greatly appreciated!
+
+Another really great way to help is if you find an interesting, or helpful way in which to use `clap`. You can either add it to the [examples/](examples) directory, or file an issue and tell me. I'm all about giving credit where credit is due :)
+
+### Testing Code
+
+To test with all features both enabled and disabled, you can run these commands:
+
+```sh
+$ cargo test --no-default-features
+$ cargo test --features "yaml unstable"
+```
+
+Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the prebuilt recipes. *Not* using `just` is perfectly fine as well, it simply bundles commands automatically.
+
+For example, to test the code, as above simply run:
+
+```sh
+$ just run-tests
+```
+
+From here on, I will list the appropriate `cargo` command as well as the `just` command.
+
+Sometimes it's helpful to only run a subset of the tests, which can be done via:
+
+```sh
+$ cargo test --test <test_name>
+
+# Or
+
+$ just run-test <test_name>
+```
+
+### Linting Code
+
+During the CI process `clap` runs against many different lints using [`clippy`](https://github.com/rust-lang-nursery/rust-clippy). In order to check if these lints pass on your own computer prior to submitting a PR you'll need a nightly compiler.
+
+In order to check the code for lints run either:
+
+```sh
+$ rustup override add nightly
+$ cargo build --features lints
+$ rustup override remove
+
+# Or
+
+$ just lint
+```
+
+### Debugging Code
+
+Another helpful technique is to see the `clap` debug output while developing features. In order to see the debug output while running the full test suite or individual tests, run:
+
+```sh
+$ cargo test --features debug
+
+# Or for individual tests
+$ cargo test --test <test_name> --features debug
+
+# The corresponding just command for individual debugging tests is:
+$ just debug <test_name>
+```
+
+### Commit Messages
+
+I use a [conventional](https://github.com/ajoslin/conventional-changelog/blob/a5505865ff3dd710cf757f50530e73ef0ca641da/conventions/angular.md) changelog format so I can update my changelog automatically using [clog](https://github.com/clog-tool/clog-cli)
+
+ * Please format your commit subject line using the following format: `TYPE(COMPONENT): MESSAGE` where `TYPE` is one of the following:
+ - `api` - An addition to the API
+ - `setting` - A new `AppSettings` variant
+ - `feat` - A new feature of an existing API
+ - `imp` - An improvement to an existing feature/API
+ - `perf` - A performance improvement
+ - `docs` - Changes to documentation only
+ - `tests` - Changes to the testing framework or tests only
+ - `fix` - A bug fix
+ - `refactor` - Code functionality doesn't change, but underlying structure may
+ - `style` - Stylistic changes only, no functionality changes
+ - `wip` - A work in progress commit (Should typically be `git rebase`'ed away)
+ - `chore` - Catch all or things that have to do with the build system, etc
+ - `examples` - Changes to existing example, or a new example
+ * The `COMPONENT` is optional, and may be a single file, directory, or logical component. Parenthesis can be omitted if you are opting not to use the `COMPONENT`.
+
+### Tests and Documentation
+
+1. Create tests for your changes
+2. **Ensure the tests are passing.** Run the tests (`cargo test --features "yaml unstable"`), alternatively `just run-tests` if you have `just` installed.
+3. **Optional** Run the lints (`cargo build --features lints`) (requires a nightly compiler), alternatively `just lint`
+4. Ensure your changes contain documentation if adding new APIs or features.
+
+### Preparing the PR
+
+1. `git rebase` into concise commits and remove `--fixup`s or `wip` commits (`git rebase -i HEAD~NUM` where `NUM` is number of commits back to start the rebase)
+2. Push your changes back to your fork (`git push origin $your-branch`)
+3. Create a pull request against `master`! (You can also create the pull request first, and we'll merge when ready. This a good way to discuss proposed changes.)
+
+### Other ways to contribute
+
+Another really great way to help is if you find an interesting, or helpful way in which to use `clap`. You can either add it to the [examples/](../examples) directory, or file an issue and tell me. I'm all about giving credit where credit is due :)
+
+### Goals
+
+There are a few goals of `clap` that I'd like to maintain throughout contributions. If your proposed changes break, or go against any of these goals we'll discuss the changes further before merging (but will *not* be ignored, all contributes are welcome!). These are by no means hard-and-fast rules, as I'm no expert and break them myself from time to time (even if by mistake or ignorance :P).
+
+* Remain backwards compatible when possible
+ - If backwards compatibility *must* be broken, use deprecation warnings if at all possible before removing legacy code
+ - This does not apply for security concerns
+* Parse arguments quickly
+ - Parsing of arguments shouldn't slow down usage of the main program
+ - This is also true of generating help and usage information (although *slightly* less stringent, as the program is about to exit)
+* Try to be cognizant of memory usage
+ - Once parsing is complete, the memory footprint of `clap` should be low since the main program is the star of the show
+* `panic!` on *developer* error, exit gracefully on *end-user* error
diff --git a/clap/.github/ISSUE_TEMPLATE.md b/clap/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..5f94a2c
--- /dev/null
+++ b/clap/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,46 @@
+<!--
+Please use the following template to assist with creating an issue and to ensure a speedy resolution. If an area is not applicable, feel free to delete the area or mark with `N/A`
+-->
+
+### Rust Version
+
+* Use the output of `rustc -V`
+
+### Affected Version of clap
+
+* Can be found in Cargo.lock of your project (i.e. `grep clap Cargo.lock`)
+
+### Bug or Feature Request Summary
+
+
+### Expected Behavior Summary
+
+
+### Actual Behavior Summary
+
+
+### Steps to Reproduce the issue
+
+
+### Sample Code or Link to Sample Code
+
+
+### Debug output
+
+Compile clap with cargo features `"debug"` such as:
+
+```toml
+[dependencies]
+clap = { version = "2", features = ["debug"] }
+```
+
+<details>
+<summary> Debug Output </summary>
+<pre>
+<code>
+
+Paste Debug Output Here
+
+</code>
+</pre>
+</details>
diff --git a/clap/.gitignore b/clap/.gitignore
new file mode 100644
index 0000000..34253e9
--- /dev/null
+++ b/clap/.gitignore
@@ -0,0 +1,27 @@
+# Compiled files
+*.o
+*.so
+*.rlib
+*.dll
+
+# Executables
+*.exe
+
+# Generated by Cargo
+/target/
+/clap-test/target/
+
+# Cargo files
+Cargo.lock
+
+# Temp files
+.*~
+
+# Backup files
+*.bak
+*.bk
+*.orig
+
+# Project files
+.vscode/*
+.idea/*
diff --git a/clap/.mention-bot b/clap/.mention-bot
new file mode 100644
index 0000000..f339f59
--- /dev/null
+++ b/clap/.mention-bot
@@ -0,0 +1,9 @@
+{
+ "findPotentialReviewers": false,
+ "alwaysNotifyForPaths": [
+ {
+ "name": "kbknapp",
+ "files": ["**/*.rs", "**/*.md", "*"]
+ }
+ ]
+}
diff --git a/clap/.travis.yml b/clap/.travis.yml
new file mode 100644
index 0000000..9eb4044
--- /dev/null
+++ b/clap/.travis.yml
@@ -0,0 +1,59 @@
+sudo: true
+language: rust
+cache: cargo
+rust:
+ - nightly
+ - beta
+ - stable
+ - 1.31.0
+matrix:
+ allow_failures:
+ - rust: nightly
+before_script:
+ - |
+ pip install git+git://github.com/kbknapp/travis-cargo.git --user &&
+ export PATH=$HOME/.local/bin:$PATH
+ - |
+ if [[ "$TRAVIS_RUST_VERSION" == "1.13.0" ]]; then
+ echo "Old Rust detected, removing version-sync dependency"
+ sed -i "/^version-sync =/d" Cargo.toml
+ rm "tests/version-numbers.rs"
+ fi
+script:
+ - |
+ travis-cargo --only stable test -- --verbose --no-default-features &&
+ travis-cargo --skip nightly test -- --verbose --features "yaml unstable" &&
+ travis-cargo --only nightly test -- --verbose --features "yaml unstable nightly" &&
+ travis-cargo --only nightly bench -- --no-run
+addons:
+ apt:
+ packages:
+ - binutils-dev
+ - libcurl4-openssl-dev
+ - libelf-dev
+ - libdw-dev
+ - libiberty-dev
+ - cmake
+ - gcc
+ - zlib1g-dev
+after_success:
+ - |
+ wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
+ tar xzf master.tar.gz &&
+ cd kcov-master &&
+ mkdir build &&
+ cd build &&
+ cmake .. &&
+ make &&
+ sudo make install &&
+ cd ../.. &&
+ rm -rf kcov-master &&
+ cargo clean &&
+ cargo test --no-run --features "yaml unstable" &&
+ for file in target/debug/*-*; do mkdir -p "target/cov/$(basename $file)"; kcov --exclude-pattern=/.cargo --verify "target/cov/$(basename $file)" "$file"; done &&
+ kcov --coveralls-id=$TRAVIS_JOB_ID --merge target/cov target/cov/* &&
+ echo "Uploaded code coverage"
+env:
+ global:
+ - TRAVIS_CARGO_NIGHTLY_FEATURE=lints
+ - secure: JLBlgHY6OEmhJ8woewNJHmuBokTNUv7/WvLkJGV8xk0t6bXBwSU0jNloXwlH7FiQTc4TccX0PumPDD4MrMgxIAVFPmmmlQOCmdpYP4tqZJ8xo189E5zk8lKF5OyaVYCs5SMmFC3cxCsKjfwGIexNu3ck5Uhwe9jI0tqgkgM3URA=
diff --git a/clap/CHANGELOG.md b/clap/CHANGELOG.md
new file mode 100644
index 0000000..d1fdd40
--- /dev/null
+++ b/clap/CHANGELOG.md
@@ -0,0 +1,2855 @@
+<a name="v2.33.0"></a>
+## v2.33.0 (2019-04-06)
+
+#### New Sponsor
+
+* Stephen Oats is now a sponsor \o/ ([823457c0](https://github.com/kbknapp/clap-rs/commit/823457c0ef5e994ed7080cf62addbfe1aa3b1833))
+* **SPONSORS.md:** fixes Josh Triplett's info in the sponsor document ([24cb5740](https://github.com/kbknapp/clap-rs/commit/24cb574090a11159b48bba105d5ec2dfb0a20e4e))
+
+#### Features
+
+* **Completions:** adds completion support for Elvish. ([e9d0562a](https://github.com/kbknapp/clap-rs/commit/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9))
+* There is a new setting to disable automatic building of `--help` and `-h` flags (`AppSettings::DisableAutoHelp`)
+
+#### Improvements
+
+* **arg_matches.rs:** add Debug implementations ([47192b7a](https://github.com/kbknapp/clap-rs/commit/47192b7a2d84ec716b81ae4af621e008a8762dc9))
+* **macros:** Support shorthand syntax for ArgGroups ([df9095e7](https://github.com/kbknapp/clap-rs/commit/df9095e75bb1e7896415251d0d4ffd8a0ebcd559))
+
+#### Documentation
+
+* Refer to macOS rather than OSX. ([ab0d767f](https://github.com/kbknapp/clap-rs/commit/ab0d767f3a5a57e2bbb97d0183c2ef63c8c77a6c))
+* **README.md:** use https for all links ([96a7639a](https://github.com/kbknapp/clap-rs/commit/96a7639a36bcb184c3f45348986883115ef1ab3a))
+
+#### Bug Fixes
+
+* add debug assertion for missing args in subcommand ArgGroup ([2699d9e5](https://github.com/kbknapp/clap-rs/commit/2699d9e51e7eadc258ba64c4e347c5d1fef61343))
+* Restore compat with Rust 1.21 ([6b263de1](https://github.com/kbknapp/clap-rs/commit/6b263de1d42ede692ec5ee55019ad2fc6386f92e))
+* Dont mention unused subcommands ([ef92e2b6](https://github.com/kbknapp/clap-rs/commit/ef92e2b639ed305bdade4741f60fa85cb0101c5a))
+* **OsValues:** Add `ExactSizeIterator` implementation ([356c69e5](https://github.com/kbknapp/clap-rs/commit/356c69e508fd25a9f0ea2d27bf80ae1d9a8d88f4))
+* **arg_enum!:**
+ * Fix comma position for valid values. ([1f1f9ff3](https://github.com/kbknapp/clap-rs/commit/1f1f9ff3fa38a43231ef8be9cfea89a32e53f518))
+ * Invalid expansions of some trailing-comma patterns ([7023184f](https://github.com/kbknapp/clap-rs/commit/7023184fca04e852c270341548d6a16207d13862))
+* **completions:** improve correctness of completions when whitespace is involved ([5a08ff29](https://github.com/kbknapp/clap-rs/commit/5a08ff295b2aa6ce29420df6252a0e3ff4441bdc))
+* **help message:** Unconditionally uses long description for subcommands ([6acc8b6a](https://github.com/kbknapp/clap-rs/commit/6acc8b6a621a765cbf513450188000d943676a30), closes [#897](https://github.com/kbknapp/clap-rs/issues/897))
+* **macros:** fixes broken pattern which prevented calling multi-argument Arg methods ([9e7a352e](https://github.com/kbknapp/clap-rs/commit/9e7a352e13aaf8025d80f2bac5c47fb32528672b))
+* **parser:** Better interaction between AllowExternalSubcommands and SubcommandRequired ([9601c95a](https://github.com/kbknapp/clap-rs/commit/9601c95a03d2b82bf265c328b4769238f1b79002))
+
+#### Minimum Required Rust
+
+* As of this release, `clap` requires `rustc 1.31.0` or greater.
+
+<a name="v2.32.0"></a>
+## v2.32.0 (2018-06-26)
+
+#### Minimum Required Rust
+
+* As of this release, `clap` requires `rustc 1.21.0` or greater.
+
+
+#### Features
+
+* **Completions:** adds completion support for Elvish. ([e9d0562a](https://github.com/kbknapp/clap-rs/commit/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9))
+
+#### Improvements
+
+* **macros:** Support shorthand syntax for ArgGroups ([df9095e7](https://github.com/kbknapp/clap-rs/commit/df9095e75bb1e7896415251d0d4ffd8a0ebcd559))
+
+#### Bug Fixes
+
+* **OsValues:** Add `ExactSizeIterator` implementation ([356c69e5](https://github.com/kbknapp/clap-rs/commit/356c69e508fd25a9f0ea2d27bf80ae1d9a8d88f4))
+* **arg_enum!:** Invalid expansions of some trailing-comma patterns ([7023184f](https://github.com/kbknapp/clap-rs/commit/7023184fca04e852c270341548d6a16207d13862))
+* **help message:** Unconditionally uses long description for subcommands ([6acc8b6a](https://github.com/kbknapp/clap-rs/commit/6acc8b6a621a765cbf513450188000d943676a30), closes [#897](https://github.com/kbknapp/clap-rs/issues/897))
+
+#### Documentation
+
+* Refer to macOS rather than OSX. ([ab0d767f](https://github.com/kbknapp/clap-rs/commit/ab0d767f3a5a57e2bbb97d0183c2ef63c8c77a6c))
+
+
+
+<a name="v2.31.2"></a>
+### v2.31.2 (2018-03-19)
+
+#### Bug Fixes
+
+* **Fish Completions:** fixes a bug that only allowed a single completion in in Fish Shell ([e8774a8](https://github.com/kbknapp/clap-rs/pull/1214/commits/e8774a84ee4a319c888036e7c595ab46451d8e48), closes [#1212](https://github.com/kbknapp/clap-rs/issues/1212))
+* **AllowExternalSubcommands**: fixes a bug where external subcommands would be blocked by a similarly named subcommand (suggestions were getting in the way). ([a410e85](https://github.com/kbknapp/clap-rs/pull/1215/commits/a410e855bcd82b05f9efa73fa8b9774dc8842c6b))
+
+#### Documentation
+
+* Fixes some typos in the `README.md` ([c8e685d7](https://github.com/kbknapp/clap-rs/commit/c8e685d76adee2a3cc06cac6952ffcf6f9548089))
+
+<a name="v2.31.1"></a>
+### v2.31.1 (2018-03-06)
+
+
+#### Improvements
+
+* **AllowMissingPositional:** improves the ability of AllowMissingPositional to allow 'skipping' to the last positional arg with '--' ([df20e6e2](https://github.com/kbknapp/clap-rs/commit/df20e6e24b4e782be0b423b484b9798e3e2efe2f))
+
+
+<a name="v2.31.0"></a>
+## v2.31.0 (2018-03-04)
+
+
+#### Features
+
+* **Arg Indices:** adds the ability to query argument value indices ([f58d0576](https://github.com/kbknapp/clap-rs/commit/f58d05767ec8133c8eb2de117cb642b9ae29ccbc))
+* **Indices:** implements an Indices<Item=&usize> iterator ([1e67be44](https://github.com/kbknapp/clap-rs/commit/1e67be44f0ccf161cc84c4e6082382072e89c302))
+* **Raw Args** adds a convenience function to `Arg` that allows implying all of `Arg::last` `Arg::allow_hyphen_values` and `Arg::multiple(true)` ([66a78f29](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2))
+
+#### Documentation
+
+* Fix some typos and markdown issues. ([935ba0dd](https://github.com/kbknapp/clap-rs/commit/935ba0dd547a69c3f636c5486795012019408794))
+* **Arg Indices:** adds the documentation for the arg index querying methods ([50bc0047](https://github.com/kbknapp/clap-rs/commit/50bc00477afa64dc6cdc5de161d3de3ba1d105a7))
+* **CONTRIBUTING.md:** fix url to clippy upstream repo to point to https://github.com/rust-lang-nursery/rust-clippy instead of https://github.com/Manishearth/rust-clippy ([42407d7f](https://github.com/kbknapp/clap-rs/commit/42407d7f21d794103cda61f49d2615aae0a4bcd9))
+* **Values:** improves the docs example of the Values iterator ([74075d65](https://github.com/kbknapp/clap-rs/commit/74075d65e8db1ddb5e2a4558009a5729d749d1b6))
+* Updates readme to hint that the `wrap_help` feature is a thing ([fc7ab227](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2))
+
+### Improvements
+
+* Cargo.toml: use codegen-units = 1 in release and bench profiles ([19f425ea](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2))
+* Adds WASM support (clap now compiles on WASM!) ([689949e5](https://github.com/kbknapp/clap-rs/commit/689949e57d390bb61bc69f3ed91f60a2105738d0))
+* Uses the short help tool-tip for PowerShell completion scripts ([ecda22ce](https://github.com/kbknapp/clap-rs/commit/ecda22ce7210ce56d7b2d1a5445dd1b8a2959656))
+
+
+<a name="v2.30.0"></a>
+## v2.30.0 (2018-02-13)
+
+#### Bug Fixes
+
+* **YAML:** Adds a missing conversion from `Arg::last` when instantiating from a YAML file ([aab77c81a5](https://github.com/kbknapp/clap-rs/pull/1175/commits/aab77c81a519b045f95946ae0dd3e850f9b93070), closes [#1160](https://github.com/kbknapp/clap-rs/issues/1173))
+
+#### Improvements
+
+* **Bash Completions:** instead of completing a generic option name, all bash completions fall back to file completions UNLESS `Arg::possible_values` was used ([872f02ae](https://github.com/kbknapp/clap-rs/commit/872f02aea900ffa376850a279eb164645e1234fa))
+* **Deps:** No longer needlessly compiles `ansi_term` on Windows since its not used ([b57ee946](https://github.com/kbknapp/clap-rs/commit/b57ee94609da3ddc897286cfba968f26ff961491), closes [#1155](https://github.com/kbknapp/clap-rs/issues/1155))
+* **Help Message:** changes the `[values: foo bar baz]` array to `[possible values: foo bar baz]` for consistency with the API ([414707e4e97](https://github.com/kbknapp/clap-rs/pull/1176/commits/414707e4e979d07bfe555247e5d130c546673708), closes [#1160](https://github.com/kbknapp/clap-rs/issues/1160))
+
+
+<a name="v2.29.4"></a>
+### v2.29.4 (2018-02-06)
+
+
+#### Bug Fixes
+
+* **Overrides Self:** fixes a bug where options with multiple values couldnt ever have multiple values ([d95907cf](https://github.com/kbknapp/clap-rs/commit/d95907cff6d011a901fe35fa00b0f4e18547a1fb))
+
+
+
+<a name="v2.29.3"></a>
+### v2.29.3 (2018-02-05)
+
+
+#### Improvements
+
+* **Overrides:** clap now supports arguments which override with themselves ([6c7a0010](https://github.com/kbknapp/clap-rs/commit/6c7a001023ca1eac1cc6ffe6c936b4c4a2aa3c45), closes [#976](https://github.com/kbknapp/clap-rs/issues/976))
+
+#### Bug Fixes
+
+* **Requirements:** fixes an issue where conflicting args would still show up as required ([e06cefac](https://github.com/kbknapp/clap-rs/commit/e06cefac97083838c0a4e1444dcad02a5c3f911e), closes [#1158](https://github.com/kbknapp/clap-rs/issues/1158))
+* Fixes a bug which disallows proper nesting of `--` ([73993fe](https://github.com/kbknapp/clap-rs/commit/73993fe30d135f682e763ec93dcb0814ed518011), closes [#1161](https://github.com/kbknapp/clap-rs/issues/1161))
+
+#### New Settings
+
+* **AllArgsOverrideSelf:** adds a new convenience setting to allow all args to override themselves ([4670325d](https://github.com/kbknapp/clap-rs/commit/4670325d1bf0369addec2ae2bcb56f1be054c924))
+
+
+
+<a name="v2.29.2"></a>
+### v2.29.2 (2018-01-16)
+
+
+#### Features
+
+* **completions/zsh.rs:**
+ * Escape possible values for options ([25561dec](https://github.com/kbknapp/clap-rs/commit/25561decf147d329b64634a14d9695673c2fc78f))
+ * Implement postional argument possible values completion ([f3b0afd2](https://github.com/kbknapp/clap-rs/commit/f3b0afd2bef8b7be97162f8a7802ddf7603dff36))
+ * Complete positional arguments properly ([e39aeab8](https://github.com/kbknapp/clap-rs/commit/e39aeab8487596046fbdbc6a226e5c8820585245))
+
+#### Bug Fixes
+
+* **completions/zsh.rs:**
+ * Add missing autoload for is-at-least ([a6522607](https://github.com/kbknapp/clap-rs/commit/a652260795d1519f6ec2a7a09ccc1258499cad7b))
+ * Don't pass -S to _arguments if Zsh is too old ([16b4f143](https://github.com/kbknapp/clap-rs/commit/16b4f143ff466b7ef18a267bc44ade0f9639109b))
+ * Maybe fix completions with mixed positionals and subcommands ([1146f0da](https://github.com/kbknapp/clap-rs/commit/1146f0da154d6796fbfcb09db8efa3593cb0d898))
+* **completions/zsh.zsh:** Remove redundant code from output ([0e185b92](https://github.com/kbknapp/clap-rs/commit/0e185b922ed1e0fd653de00b4cd8d567d72ff68e), closes [#1142](https://github.com/kbknapp/clap-rs/issues/1142))
+
+
+
+<a name="2.29.1"></a>
+### 2.29.1 (2018-01-09)
+
+
+#### Documentation
+
+* fixes broken links. ([56e734b8](https://github.com/kbknapp/clap-rs/commit/56e734b839303d733d2e5baf7dac39bd7b97b8e4))
+* updates contributors list ([e1313a5a](https://github.com/kbknapp/clap-rs/commit/e1313a5a0f69d8f4016f73b860a63af8318a6676))
+
+#### Performance
+
+* further debloating by removing generics from error cases ([eb8d919e](https://github.com/kbknapp/clap-rs/commit/eb8d919e6f3443db279ba0c902f15d76676c02dc))
+* debloats clap by deduplicating logic and refactors ([03e413d7](https://github.com/kbknapp/clap-rs/commit/03e413d7175d35827cd7d8908d47dbae15a849a3))
+
+#### Bug Fixes
+
+* fixes the ripgrep benchmark by adding a value to a flag that expects it ([d26ab2b9](https://github.com/kbknapp/clap-rs/commit/d26ab2b97cf9c0ea675b440b7b0eaf6ac3ad01f4))
+* **bash completion:** Change the bash completion script code generation to support hyphens. ([ba7f1d18](https://github.com/kbknapp/clap-rs/commit/ba7f1d18eba7a07ce7f57e0981986f66c994b639))
+* **completions/zsh.rs:** Fix completion of long option values ([46365cf8](https://github.com/kbknapp/clap-rs/commit/46365cf8be5331ba04c895eb183e2f230b5aad51))
+
+
+<a name="2.29.0"></a>
+## 2.29.0 (2017-12-02)
+
+
+#### API Additions
+
+* **Arg:** adds Arg::hide_env_values(bool) which allows one to hide any current env values and display only the key in help messages ([fb41d062](https://github.com/kbknapp/clap-rs/commit/fb41d062eedf37cb4f805c90adca29909bd197d7))
+
+
+
+<a name="2.28.0"></a>
+## 2.28.0 (2017-11-28)
+
+The minimum required Rust is now 1.20. This was done to start using bitflags 1.0 and having >1.0 deps is a *very good* thing!
+
+#### Documentation
+
+* changes the demo version to 2.28 to stay in sync ([ce6ca492](https://github.com/kbknapp/clap-rs/commit/ce6ca492c7510ab6474075806360b96081b021a9))
+* Fix URL path to github hosted files ([ce72aada](https://github.com/kbknapp/clap-rs/commit/ce72aada56a9581d4a6cb4bf9bdb861c3906f8df), closes [#1106](https://github.com/kbknapp/clap-rs/issues/1106))
+* fix typo ([002b07fc](https://github.com/kbknapp/clap-rs/commit/002b07fc98a1c85acb66296b1eec0b2aba906125))
+* **README.md:** updates the readme and pulls out some redundant sections ([db6caf86](https://github.com/kbknapp/clap-rs/commit/db6caf8663747e679d2f4ed3bd127f33476754aa))
+
+#### Improvements
+
+* adds '[SUBCOMMAND]' to usage strings with only AppSettings::AllowExternalSubcommands is used with no other subcommands ([e78bb757](https://github.com/kbknapp/clap-rs/commit/e78bb757a3df16e82d539e450c06767a6bfcf859), closes [#1093](https://github.com/kbknapp/clap-rs/issues/1093))
+
+#### API Additions
+
+* Adds Arg::case_insensitive(bool) which allows matching Arg::possible_values without worrying about ASCII case ([1fec268e](https://github.com/kbknapp/clap-rs/commit/1fec268e51736602e38e67c76266f439e2e0ef12), closes [#1118](https://github.com/kbknapp/clap-rs/issues/1118))
+* Adds the traits to be used with the clap-derive crate to be able to use Custom Derive ([6f4c3412](https://github.com/kbknapp/clap-rs/commit/6f4c3412415e882f5ca2cc3fbd6d4dce79440828))
+
+#### Bug Fixes
+
+* Fixes a regression where --help couldn't be overridden ([a283d69f](https://github.com/kbknapp/clap-rs/commit/a283d69fc08aa016ae1bf9ba010012abecc7ba69), closes [#1112](https://github.com/kbknapp/clap-rs/issues/1112))
+* fixes a bug that allowed options to pass parsing when no value was provided ([2fb75821](https://github.com/kbknapp/clap-rs/commit/2fb758219c7a60d639da67692e100b855a8165ac), closes [#1105](https://github.com/kbknapp/clap-rs/issues/1105))
+* ignore PropagateGlobalValuesDown deprecation warning ([f61ce3f5](https://github.com/kbknapp/clap-rs/commit/f61ce3f55fe65e16b3db0bd4facdc4575de22767), closes [#1086](https://github.com/kbknapp/clap-rs/issues/1086))
+
+#### Deps
+
+* Updates `bitflags` to 1.0
+
+
+
+<a name="v2.27.1"></a>
+## v2.27.1 (2017-10-24)
+
+
+#### Bug Fixes
+
+* Adds `term_size` as an optional dependency (with feature `wrap_help`) to fix compile bug
+
+<a name="v2.27.0"></a>
+## v2.27.0 (2017-10-24)
+
+** This release raises the minimum required version of Rust to 1.18 **
+
+** This release also contains a very minor breaking change to fix a bug **
+
+The only CLIs affected will be those using unrestrained multiple values and subcommands where the
+subcommand name can coincide with one of the multiple values.
+
+See the commit [0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31) for full details.
+
+
+#### Bug Fixes
+
+* Values from global args are now propagated UP and DOWN!
+* fixes a bug where using AppSettings::AllowHyphenValues would allow invalid arguments even when there is no way for them to be valid ([77ed4684](https://github.com/kbknapp/clap-rs/commit/77ed46841fc0263d7aa32fcc5cc49ef703b37c04), closes [#1066](https://github.com/kbknapp/clap-rs/issues/1066))
+* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value ([0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31), closes [#1031](https://github.com/kbknapp/clap-rs/issues/1031), breaks [#](https://github.com/kbknapp/clap-rs/issues/), [#](https://github.com/kbknapp/clap-rs/issues/))
+* fixes a bug that prevented number_of_values and default_values to be used together ([5eb342a9](https://github.com/kbknapp/clap-rs/commit/5eb342a99dde07b0f011048efde3e283bc1110fc), closes [#1050](https://github.com/kbknapp/clap-rs/issues/1050), [#1056](https://github.com/kbknapp/clap-rs/issues/1056))
+* fixes a bug that didn't allow args with default values to have conflicts ([58b5b4be](https://github.com/kbknapp/clap-rs/commit/58b5b4be315280888d50d9b15119b91a9028f050), closes [#1071](https://github.com/kbknapp/clap-rs/issues/1071))
+* fixes a panic when using global args and calling App::get_matches_from_safe_borrow multiple times ([d86ec797](https://github.com/kbknapp/clap-rs/commit/d86ec79742c77eb3f663fb30e225954515cf25bb), closes [#1076](https://github.com/kbknapp/clap-rs/issues/1076))
+* fixes issues and potential regressions with global args values not being propagated properly or at all ([a43f9dd4](https://github.com/kbknapp/clap-rs/commit/a43f9dd4aaf1864dd14a3c28dec89ccdd70c61e5), closes [#1010](https://github.com/kbknapp/clap-rs/issues/1010), [#1061](https://github.com/kbknapp/clap-rs/issues/1061), [#978](https://github.com/kbknapp/clap-rs/issues/978))
+* fixes a bug where default values are not applied if the option supports zero values ([9c248cbf](https://github.com/kbknapp/clap-rs/commit/9c248cbf7d8a825119bc387c23e9a1d1989682b0), closes [#1047](https://github.com/kbknapp/clap-rs/issues/1047))
+
+#### Documentation
+
+* adds addtional blurbs about using multiples with subcommands ([03455b77](https://github.com/kbknapp/clap-rs/commit/03455b7751a757e7b2f6ffaf2d16168539c99661))
+* updates the docs to reflect changes to global args and that global args values can now be propagated back up the stack ([ead076f0](https://github.com/kbknapp/clap-rs/commit/ead076f03ada4c322bf3e34203925561ec496d87))
+* add html_root_url attribute ([e67a061b](https://github.com/kbknapp/clap-rs/commit/e67a061bcf567c6518d6c2f58852e01f02764b22))
+* sync README version numbers with crate version ([5536361b](https://github.com/kbknapp/clap-rs/commit/5536361bcda29887ed86bb68e43d0b603cbc423f))
+
+#### Improvements
+
+* args that have require_delimiter(true) is now reflected in help and usage strings ([dce61699](https://github.com/kbknapp/clap-rs/commit/dce616998ed9bd95e8ed3bec1f09a4883da47b85), closes [#1052](https://github.com/kbknapp/clap-rs/issues/1052))
+* if all subcommands are hidden, the subcommands section of the help message is no longer displayed ([4ae7b046](https://github.com/kbknapp/clap-rs/commit/4ae7b0464750bc07ec80ece38e43f003fdd1b8ae), closes [#1046](https://github.com/kbknapp/clap-rs/issues/1046))
+
+#### Breaking Changes
+
+* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value ([0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31), closes [#1031](https://github.com/kbknapp/clap-rs/issues/1031), breaks [#](https://github.com/kbknapp/clap-rs/issues/), [#](https://github.com/kbknapp/clap-rs/issues/))
+
+#### Deprecations
+
+* **AppSettings::PropagateGlobalValuesDown:** this setting is no longer required to propagate values down or up ([2bb5ddce](https://github.com/kbknapp/clap-rs/commit/2bb5ddcee61c791ca1aaca494fbeb4bd5e277488))
+
+
+
+<a name="v2.26.2"></a>
+### v2.26.2 (2017-09-14)
+
+
+#### Improvements
+
+* if all subcommands are hidden, the subcommands section of the help message is no longer displayed ([4ae7b046](https://github.com/kbknapp/clap-rs/commit/4ae7b0464750bc07ec80ece38e43f003fdd1b8ae), closes [#1046](https://github.com/kbknapp/clap-rs/issues/1046))
+
+#### Bug Fixes
+
+* fixes a bug where default values are not applied if the option supports zero values ([9c248cbf](https://github.com/kbknapp/clap-rs/commit/9c248cbf7d8a825119bc387c23e9a1d1989682b0), closes [#1047](https://github.com/kbknapp/clap-rs/issues/1047))
+
+
+
+<a name="v2.26.1"></a>
+### v2.26.1 (2017-09-14)
+
+
+#### Bug Fixes
+
+* fixes using require_equals(true) and min_values(0) together ([10ae208f](https://github.com/kbknapp/clap-rs/commit/10ae208f68518eff6e98166724065745f4083174), closes [#1044](https://github.com/kbknapp/clap-rs/issues/1044))
+* escape special characters in zsh and fish completions ([87e019fc](https://github.com/kbknapp/clap-rs/commit/87e019fc84ba6193a8c4ddc26c61eb99efffcd25))
+* avoid panic generating default help msg if term width set to 0 due to bug in textwrap 0.7.0 ([b3eadb0d](https://github.com/kbknapp/clap-rs/commit/b3eadb0de516106db4e08f078ad32e8f6d6e7a57))
+* Change `who's` -> `whose` ([53c1ffe8](https://github.com/kbknapp/clap-rs/commit/53c1ffe87f38b05d8804a0f7832412a952845349))
+* adds a debug assertion to ensure all args added to groups actually exist ([7ad123e2](https://github.com/kbknapp/clap-rs/commit/7ad123e2c02577e3ca30f7e205181e896b157d11), closes [#917](https://github.com/kbknapp/clap-rs/issues/917))
+* fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value ([ab2f4c9e](https://github.com/kbknapp/clap-rs/commit/ab2f4c9e563e36ec739a4b55d5a5b76fdb9e9fa4), closes [#960](https://github.com/kbknapp/clap-rs/issues/960))
+* fixes a bug where positional argument help text is misaligned ([54c16836](https://github.com/kbknapp/clap-rs/commit/54c16836dea4651806a2cfad53146a83fa3abf21))
+* **Help Message:** fixes long_about not being usable ([a8257ea0](https://github.com/kbknapp/clap-rs/commit/a8257ea0ffb812e552aca256c4a3d2aebfd8065b), closes [#1043](https://github.com/kbknapp/clap-rs/issues/1043))
+* **Suggestions:** output for flag after subcommand ([434ea5ba](https://github.com/kbknapp/clap-rs/commit/434ea5ba71395d8c1afcf88e69f0b0d8339b01a1))
+
+
+
+<a name="v2.26.0"></a>
+## v2.26.0 (2017-07-29)
+
+Minimum version of Rust is now v1.13.0 (Stable)
+
+
+#### Improvements
+
+* bumps unicode-segmentation to v1.2 ([cd7b40a2](https://github.com/kbknapp/clap-rs/commit/cd7b40a21c77bae17ba453c5512cb82b7d1ce474))
+
+
+#### Performance
+
+* update textwrap to version 0.7.0 ([c2d4e637](https://github.com/kbknapp/clap-rs/commit/c2d4e63756a6f070e38c16dff846e9b0a53d6f93))
+
+
+
+
+<a name="v2.25.1"></a>
+### v2.25.1 (2017-07-21)
+
+#### Improvements
+
+* impl Default for Values + OsValues for any lifetime. ([fb7d6231f1](https://github.com/kbknapp/clap-rs/commit/fb7d6231f13a2f79f411e62dca210b7dc9994c18))
+
+#### Documentation
+
+* Various documentation typos and grammar fixes
+
+<a name="v2.25.0"></a>
+### v2.25.0 (2017-06-20)
+
+
+#### Features
+
+* use textwrap crate for wrapping help texts ([b93870c1](https://github.com/kbknapp/clap-rs/commit/b93870c10ae3bd90d233c586a33e086803117285))
+
+#### Improvements
+
+* **Suggestions:** suggests to use flag after subcommand when applicable ([2671ca72](https://github.com/kbknapp/clap-rs/commit/2671ca7260119d4311d21c4075466aafdd9da734))
+* Bumps bitflags crate to v0.9
+
+#### Documentation
+
+* Change `who's` -> `whose` ([53c1ffe8](https://github.com/kbknapp/clap-rs/commit/53c1ffe87f38b05d8804a0f7832412a952845349))
+
+#### Documentation
+
+* **App::template:** adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template ([cbea3d5a](https://github.com/kbknapp/clap-rs/commit/cbea3d5acf3271a7a734498c4d99c709941c331e), closes [#949](https://github.com/kbknapp/clap-rs/issues/949))
+* **Arg::allow_hyphen_values:** updates the docs to include warnings for allow_hyphen_values and multiple(true) used together ([f9b0d657](https://github.com/kbknapp/clap-rs/commit/f9b0d657835d3f517f313d70962177dc30acf4a7))
+* **README.md:**
+ * added a warning about using ~ deps ([821929b5](https://github.com/kbknapp/clap-rs/commit/821929b51bd60213955705900a436c9a64fcb79f), closes [#964](https://github.com/kbknapp/clap-rs/issues/964))
+* **clap_app!:** adds using the @group specifier to the macro docs ([826048cb](https://github.com/kbknapp/clap-rs/commit/826048cb3cbc0280169303f1498ff0a2b7395883), closes [#932](https://github.com/kbknapp/clap-rs/issues/932))
+
+
+
+<a name="v2.24.2"></a>
+### v2.24.2 (2017-05-15)
+
+
+#### Bug Fixes
+
+* adds a debug assertion to ensure all args added to groups actually exist ([14f6b8f3](https://github.com/kbknapp/clap-rs/commit/14f6b8f3a2f6df73aeeec9c54a54909b1acfc158), closes [#917](https://github.com/kbknapp/clap-rs/issues/917))
+* fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value ([ebf73a09](https://github.com/kbknapp/clap-rs/commit/ebf73a09db6f3c03c19cdd76b1ba6113930e1643), closes [#960](https://github.com/kbknapp/clap-rs/issues/960))
+* fixes a bug where positional argument help text is misaligned ([54c16836](https://github.com/kbknapp/clap-rs/commit/54c16836dea4651806a2cfad53146a83fa3abf21))
+
+#### Documentation
+
+* **App::template:** adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template ([cf569438](https://github.com/kbknapp/clap-rs/commit/cf569438f309c199800bb8e46c9f140187de69d7), closes [#949](https://github.com/kbknapp/clap-rs/issues/949))
+* **Arg::allow_hyphen_values:** updates the docs to include warnings for allow_hyphen_values and multiple(true) used together ([ded5a2f1](https://github.com/kbknapp/clap-rs/commit/ded5a2f15474d4a5bd46a67b130ccb8b6781bd01))
+* **clap_app!:** adds using the @group specifier to the macro docs ([fe85fcb1](https://github.com/kbknapp/clap-rs/commit/fe85fcb1772b61f13b20b7ea5290e2437a76190c), closes [#932](https://github.com/kbknapp/clap-rs/issues/932))
+
+
+
+<a name="v2.24.0"></a>
+### v2.24.0 (2017-05-07)
+
+
+#### Bug Fixes
+
+* fixes a bug where args with last(true) and required(true) set were not being printed in the usage string ([3ac533fe](https://github.com/kbknapp/clap-rs/commit/3ac533fedabf713943eedf006f830a5a486bbe80), closes [#944](https://github.com/kbknapp/clap-rs/issues/944))
+* fixes a bug that was printing the arg name, instead of value name when Arg::last(true) was used ([e1fe8ac3](https://github.com/kbknapp/clap-rs/commit/e1fe8ac3bc1f9cf4e36df0d881f8419755f1787b), closes [#940](https://github.com/kbknapp/clap-rs/issues/940))
+* fixes a bug where flags were parsed as flags AND positional values when specific combinations of settings were used ([20f83292](https://github.com/kbknapp/clap-rs/commit/20f83292d070038b8cee2a6b47e91f6b0a2f7871), closes [#946](https://github.com/kbknapp/clap-rs/issues/946))
+
+
+
+<a name="v2.24.0"></a>
+## v2.24.0 (2017-05-05)
+
+
+#### Documentation
+
+* **README.md:** fix some typos ([fa34deac](https://github.com/kbknapp/clap-rs/commit/fa34deac079f334c3af97bb7fb151880ba8887f8))
+
+#### API Additions
+
+* **Arg:** add `default_value_os` ([d5ef8955](https://github.com/kbknapp/clap-rs/commit/d5ef8955414b1587060f7218385256105b639c88))
+* **arg_matches.rs:** Added a Default implementation for Values and OsValues iterators. ([0a4384e3](https://github.com/kbknapp/clap-rs/commit/0a4384e350eed74c2a4dc8964c203f21ac64897f))
+
+
+<a name="v2.23.2"></a>
+### v2.23.2 (2017-04-19)
+
+
+#### Bug Fixes
+
+* **PowerShell Completions:** fixes a bug where powershells completions cant be used if no subcommands are defined ([a8bce558](https://github.com/kbknapp/clap-rs/commit/a8bce55837dc4e0fb187dc93180884a40ae09c6f), closes [#931](https://github.com/kbknapp/clap-rs/issues/931))
+
+#### Improvements
+
+* bumps term_size to take advantage of better terminal dimension handling ([e05100b7](https://github.com/kbknapp/clap-rs/commit/e05100b73d74066a90876bf38f952adf5e8ee422))
+* **PowerShell Completions:** massively dedups subcommand names in the generate script to make smaller scripts that are still functionally equiv ([85b0e1cc](https://github.com/kbknapp/clap-rs/commit/85b0e1cc4b9755dda75a93d898d79bc38631552b))
+
+#### Documentation
+
+* Fix a typo the minimum rust version required ([71dabba3](https://github.com/kbknapp/clap-rs/commit/71dabba3ea0a17c88b0e2199c9d99f0acbf3bc17))
+
+<a name="v2.23.1"></a>
+### v2.23.1 (2017-04-05)
+
+
+#### Bug Fixes
+
+* fixes a missing newline character in the autogenerated help and version messages in some instances ([5ae9007d](https://github.com/kbknapp/clap-rs/commit/5ae9007d984ae94ae2752df51bcbaeb0ec89bc15))
+
+
+<a name="v2.23.0"></a>
+## v2.23.0 (2017-04-05)
+
+
+#### API Additions
+
+* `App::long_about`
+* `App::long_version`
+* `App::print_long_help`
+* `App::write_long_help`
+* `App::print_long_version`
+* `App::write_long_version`
+* `Arg::long_help`
+
+#### Features
+
+* allows distinguishing between short and long version messages (-V/short or --version/long) ([59272b06](https://github.com/kbknapp/clap-rs/commit/59272b06cc213289dc604dbc694cb95d383a5d68))
+* allows distinguishing between short and long help with subcommands in the same manner as args ([6b371891](https://github.com/kbknapp/clap-rs/commit/6b371891a1702173a849d1e95f9fecb168bf6fc4))
+* allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used) ([ef1b24c3](https://github.com/kbknapp/clap-rs/commit/ef1b24c3a0dff2f58c5e2e90880fbc2b69df20ee))
+* **clap_app!:** adds support for arg names with hyphens similar to longs with hyphens ([f7a88779](https://github.com/kbknapp/clap-rs/commit/f7a8877978c8f90e6543d4f0d9600c086cf92cd7), closes [#869](https://github.com/kbknapp/clap-rs/issues/869))
+
+#### Bug Fixes
+
+* fixes a bug that wasn't allowing help and version to be properly overridden ([8b2ceb83](https://github.com/kbknapp/clap-rs/commit/8b2ceb8368bcb70689fadf1c7f4b9549184926c1), closes [#922](https://github.com/kbknapp/clap-rs/issues/922))
+
+#### Documentation
+
+* **clap_app!:** documents the `--("some-arg")` method for using args with hyphens inside them ([bc08ef3e](https://github.com/kbknapp/clap-rs/commit/bc08ef3e185393073d969d301989b6319c616c1f), closes [#919](https://github.com/kbknapp/clap-rs/issues/919))
+
+
+
+<a name="v2.22.2"></a>
+### v2.22.2 (2017-03-30)
+
+
+#### Bug Fixes
+
+* **Custom Usage Strings:** fixes the usage string regression when using help templates ([0e4fd96d](https://github.com/kbknapp/clap-rs/commit/0e4fd96d74280d306d09e60ac44f938a82321769))
+
+
+
+<a name="v2.22.1"></a>
+### v2.22.1 (2017-03-24)
+
+
+#### Bug Fixes
+
+* **usage:** fixes a big regression with custom usage strings ([2c41caba](https://github.com/kbknapp/clap-rs/commit/2c41caba3c7d723a2894e315d04da796b0e97759))
+
+<a name="v2.22.0"></a>
+## v2.22.0 (2017-03-23)
+
+#### API Additions
+
+* **App::name:** adds the ability to change the name of the App instance after creation ([d49e8292](https://github.com/kbknapp/clap-rs/commit/d49e8292b026b06e2b70447cd9f08299f4fcba76), closes [#908](https://github.com/kbknapp/clap-rs/issues/908))
+* **Arg::hide_default_value:** adds ability to hide the default value of an argument from the help string ([89e6ea86](https://github.com/kbknapp/clap-rs/commit/89e6ea861e16a1ad56757ca12f6b32d02253e44a), closes [#902](https://github.com/kbknapp/clap-rs/issues/902))
+
+
+<a name="v2.21.3"></a>
+### v2.21.3 (2017-03-23)
+
+#### Bug Fixes
+
+* **yaml:** adds support for loading author info from yaml ([e04c390c](https://github.com/kbknapp/clap-rs/commit/e04c390c597a55fa27e724050342f16c42f1c5c9))
+
+
+<a name="v2.21.2"></a>
+### v2.21.2 (2017-03-17)
+
+
+#### Improvements
+
+* add fish subcommand help support ([f8f68cf8](https://github.com/kbknapp/clap-rs/commit/f8f68cf8251669aef4539a25a7c1166f0ac81ea6))
+* options that use `require_equals(true)` now display the equals sign in help messages, usage strings, and errors" ([c8eb0384](https://github.com/kbknapp/clap-rs/commit/c8eb0384d394d2900ccdc1593099c97808a3fa05), closes [#903](https://github.com/kbknapp/clap-rs/issues/903))
+
+
+#### Bug Fixes
+
+* setting the max term width now correctly propagates down through child subcommands
+
+
+
+<a name="v2.21.1"></a>
+### v2.21.1 (2017-03-12)
+
+
+#### Bug Fixes
+
+* **ArgRequiredElseHelp:** fixes the precedence of this error to prioritize over other error messages ([74b751ff](https://github.com/kbknapp/clap-rs/commit/74b751ff2e3631e337b7946347c1119829a41c53), closes [#895](https://github.com/kbknapp/clap-rs/issues/895))
+* **Positionals:** fixes some regression bugs resulting from old asserts in debug mode. ([9a3bc98e](https://github.com/kbknapp/clap-rs/commit/9a3bc98e9b55e7514b74b73374c5ac8b6e5e0508), closes [#896](https://github.com/kbknapp/clap-rs/issues/896))
+
+
+
+<a name="v2.21.0"></a>
+## v2.21.0 (2017-03-09)
+
+#### Performance
+
+* doesn't run `arg_post_processing` on multiple values anymore ([ec516182](https://github.com/kbknapp/clap-rs/commit/ec5161828729f6a53f0fccec8648f71697f01f78))
+* changes internal use of `VecMap` to `Vec` for matched values of `Arg`s ([22bf137a](https://github.com/kbknapp/clap-rs/commit/22bf137ac581684c6ed460d2c3c640c503d62621))
+* vastly reduces the amount of cloning when adding non-global args minus when they're added from `App::args` which is forced to clone ([8da0303b](https://github.com/kbknapp/clap-rs/commit/8da0303bc02db5fe047cfc0631a9da41d9dc60f7))
+* refactor to remove unneeded vectors and allocations and checks for significant performance increases ([0efa4119](https://github.com/kbknapp/clap-rs/commit/0efa4119632f134fc5b8b9695b007dd94b76735d))
+
+#### Documentation
+
+* Fix examples link in CONTRIBUTING.md ([60cf875d](https://github.com/kbknapp/clap-rs/commit/60cf875d67a252e19bb85054be57696fac2c57a1))
+
+#### Improvements
+
+* when `AppSettings::SubcommandsNegateReqs` and `ArgsNegateSubcommands` are used, a new more accurate double line usage string is shown ([50f02300](https://github.com/kbknapp/clap-rs/commit/50f02300d81788817acefef0697e157e01b6ca32), closes [#871](https://github.com/kbknapp/clap-rs/issues/871))
+
+#### API Additions
+
+* **Arg::last:** adds the ability to mark a positional argument as 'last' which means it should be used with `--` syntax and can be accessed early ([6a7aea90](https://github.com/kbknapp/clap-rs/commit/6a7aea9043b83badd9ab038b4ecc4c787716147e), closes [#888](https://github.com/kbknapp/clap-rs/issues/888))
+* provides `default_value_os` and `default_value_if[s]_os` ([0f2a3782](https://github.com/kbknapp/clap-rs/commit/0f2a378219a6930748d178ba350fe5925be5dad5), closes [#849](https://github.com/kbknapp/clap-rs/issues/849))
+* provides `App::help_message` and `App::version_message` which allows one to override the auto-generated help/version flag associated help ([389c413](https://github.com/kbknapp/clap-rs/commit/389c413b7023dccab8c76aa00577ea1d048e7a99), closes [#889](https://github.com/kbknapp/clap-rs/issues/889))
+
+#### New Settings
+
+* **InferSubcommands:** adds a setting to allow one to infer shortened subcommands or aliases (i.e. for subcommmand "test", "t", "te", or "tes" would be allowed assuming no other ambiguities) ([11602032](https://github.com/kbknapp/clap-rs/commit/11602032f6ff05881e3adf130356e37d5e66e8f9), closes [#863](https://github.com/kbknapp/clap-rs/issues/863))
+
+#### Bug Fixes
+
+* doesn't print the argument sections in the help message if all args in that section are hidden ([ce5ee5f5](https://github.com/kbknapp/clap-rs/commit/ce5ee5f5a76f838104aeddd01c8ec956dd347f50))
+* doesn't include the various [ARGS] [FLAGS] or [OPTIONS] if the only ones available are hidden ([7b4000af](https://github.com/kbknapp/clap-rs/commit/7b4000af97637703645c5fb2ac8bb65bd546b95b), closes [#882](https://github.com/kbknapp/clap-rs/issues/882))
+* now correctly shows subcommand as required in the usage string when AppSettings::SubcommandRequiredElseHelp is used ([8f0884c1](https://github.com/kbknapp/clap-rs/commit/8f0884c1764983a49b45de52a1eddf8d721564d8))
+* fixes some memory leaks when an error is detected and clap exits ([8c2dd287](https://github.com/kbknapp/clap-rs/commit/8c2dd28718262ace4ae0db98563809548e02a86b))
+* fixes a trait that's marked private accidentlly, but should be crate internal public ([1ae21108](https://github.com/kbknapp/clap-rs/commit/1ae21108015cea87e5360402e1747025116c7878))
+* **Completions:** fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts ([5e9b9cf4](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94), closes [#846](https://github.com/kbknapp/clap-rs/issues/846))
+
+#### Features
+
+* **Options:** adds the ability to require the equals syntax with options --opt=val ([f002693d](https://github.com/kbknapp/clap-rs/commit/f002693dec6a6959c4e9590cb7b7bfffd6d6e5bc), closes [#833](https://github.com/kbknapp/clap-rs/issues/833))
+
+
+
+<a name="v2.20.5"></a>
+### v2.20.5 (2017-02-18)
+
+
+#### Bug Fixes
+
+* **clap_app!:** fixes a critical bug of a missing fragment specifier when using `!property` style tags. ([5635c1f94](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94))
+
+
+<a name="v2.20.4"></a>
+### v2.20.4 (2017-02-15)
+
+
+#### Bug Fixes
+
+* **Completions:** fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts ([5e9b9cf4](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94), closes [#846](https://github.com/kbknapp/clap-rs/issues/846))
+
+#### Documentation
+
+* Fix examples link in CONTRIBUTING.md ([60cf875d](https://github.com/kbknapp/clap-rs/commit/60cf875d67a252e19bb85054be57696fac2c57a1))
+
+
+<a name="v2.20.3"></a>
+### v2.20.3 (2017-02-03)
+
+
+#### Documentation
+
+* **Macros:** adds a warning about changing values in Cargo.toml not triggering a rebuild automatically ([112aea3e](https://github.com/kbknapp/clap-rs/commit/112aea3e42ae9e0c0a2d33ebad89496dbdd95e5d), closes [#838](https://github.com/kbknapp/clap-rs/issues/838))
+
+#### Bug Fixes
+
+* fixes a println->debugln typo ([279aa62e](https://github.com/kbknapp/clap-rs/commit/279aa62eaf08f56ce090ba16b937bc763cbb45be))
+* fixes bash completions for commands that have an underscore in the name ([7f5cfa72](https://github.com/kbknapp/clap-rs/commit/7f5cfa724f0ac4e098f5fe466c903febddb2d994), closes [#581](https://github.com/kbknapp/clap-rs/issues/581))
+* fixes a bug where ZSH completions would panic if the binary name had an underscore in it ([891a2a00](https://github.com/kbknapp/clap-rs/commit/891a2a006f775e92c556dda48bb32fac9807c4fb), closes [#581](https://github.com/kbknapp/clap-rs/issues/581))
+* allow final word to be wrapped in wrap_help ([564c5f0f](https://github.com/kbknapp/clap-rs/commit/564c5f0f1730f4a2c1cdd128664f1a981c31dcd4), closes [#828](https://github.com/kbknapp/clap-rs/issues/828))
+* fixes a bug where global args weren't included in the generated completion scripts ([9a1e006e](https://github.com/kbknapp/clap-rs/commit/9a1e006eb75ad5a6057ebd119aa90f7e06c0ace8), closes [#841](https://github.com/kbknapp/clap-rs/issues/841))
+
+
+
+<a name="v2.20.2"></a>
+### v2.20.2 (2017-02-03)
+
+#### Bug Fixes
+
+* fixes a critical bug where subcommand settings were being propogated too far ([74648c94](https://github.com/kbknapp/clap-rs/commit/74648c94b893df542bfa5bb595e68c7bb8167e36), closes [#832](https://github.com/kbknapp/clap-rs/issues/832))
+
+
+#### Improvements
+
+* adds ArgGroup::multiple to the supported YAML fields for building ArgGroups from YAML ([d8590037](https://github.com/kbknapp/clap-rs/commit/d8590037ce07dafd8cd5b26928aa4a9fd3018288), closes [#840](https://github.com/kbknapp/clap-rs/issues/840))
+
+<a name="v2.20.1"></a>
+### v2.20.1 (2017-01-31)
+
+#### Bug Fixes
+
+* allow final word to be wrapped in wrap_help ([564c5f0f](https://github.com/kbknapp/clap-rs/commit/564c5f0f1730f4a2c1cdd128664f1a981c31dcd4), closes [#828](https://github.com/kbknapp/clap-rs/issues/828))
+* actually show character in debug output ([84d8c547](https://github.com/kbknapp/clap-rs/commit/84d8c5476de95b7f37d61888bc4f13688b712434))
+* include final character in line lenght ([aff4ba18](https://github.com/kbknapp/clap-rs/commit/aff4ba18da8147e1259b04b0bfbc1fcb5c78a3c0))
+
+#### Improvements
+
+* updates libc and term_size deps for the libc version conflict ([6802ac4a](https://github.com/kbknapp/clap-rs/commit/6802ac4a59c142cda9ec55ca0c45ae5cb9a6ab55))
+
+#### Documentation
+
+* fix link from app_from_crate! to crate_authors! (#822) ([5b29be9b](https://github.com/kbknapp/clap-rs/commit/5b29be9b073330ab1f7227cdd19fe4aab39d5dcb))
+* fix spelling of "guaranteed" ([4f30a65b](https://github.com/kbknapp/clap-rs/commit/4f30a65b9c03eb09607eb91a929a6396637dc105))
+
+<a name="v2.20.0"></a>
+
+#### New Settings
+
+* **ArgsNegateSubcommands:** disables args being allowed between subcommands ([5e2af8c9](https://github.com/kbknapp/clap-rs/commit/5e2af8c96adb5ab75fa2d1536237ebcb41869494), closes [#793](https://github.com/kbknapp/clap-rs/issues/793))
+* **DontCollapseArgsInUsage:** disables the collapsing of positional args into `[ARGS]` in the usage string ([c2978afc](https://github.com/kbknapp/clap-rs/commit/c2978afc61fb46d5263ab3b2d87ecde1c9ce1553), closes [#769](https://github.com/kbknapp/clap-rs/issues/769))
+* **DisableHelpSubcommand:** disables building the `help` subcommand ([a10fc859](https://github.com/kbknapp/clap-rs/commit/a10fc859ee20159fbd9ff4337be59b76467a64f2))
+* **AllowMissingPositional:** allows one to implement `$ prog [optional] <required>` style CLIs where the second postional argument is required, but the first is optional ([1110fdc7](https://github.com/kbknapp/clap-rs/commit/1110fdc7a345c108820dc45783a9bf893fa4c214), closes [#636](https://github.com/kbknapp/clap-rs/issues/636))
+* **PropagateGlobalValuesDown:** automatically propagats global arg's values down through *used* subcommands ([985536c8](https://github.com/kbknapp/clap-rs/commit/985536c8ebcc09af98aac835f42a8072ad58c262), closes [#694](https://github.com/kbknapp/clap-rs/issues/694))
+
+#### API Additions
+
+##### Arg
+
+* **Arg::value_terminator:** adds the ability to terminate multiple values with a given string or char ([be64ce0c](https://github.com/kbknapp/clap-rs/commit/be64ce0c373efc106384baca3f487ea99fe7b8cf), closes [#782](https://github.com/kbknapp/clap-rs/issues/782))
+* **Arg::default_value_if[s]:** adds new methods for *conditional* default values (such as a particular value from another argument was used) ([eb4010e7](https://github.com/kbknapp/clap-rs/commit/eb4010e7b21724447ef837db11ac441915728f22))
+* **Arg::requires_if[s]:** adds the ability to *conditionally* require additional args (such as if a particular value was used) ([198449d6](https://github.com/kbknapp/clap-rs/commit/198449d64393c265f0bc327aaeac23ec4bb97226))
+* **Arg::required_if[s]:** adds the ability for an arg to be *conditionally* required (i.e. "arg X is only required if arg Y was used with value Z") ([ee9cfddf](https://github.com/kbknapp/clap-rs/commit/ee9cfddf345a6b5ae2af42ba72aa5c89e2ca7f59))
+* **Arg::validator_os:** adds ability to validate values which may contain invalid UTF-8 ([47232498](https://github.com/kbknapp/clap-rs/commit/47232498a813db4f3366ccd3e9faf0bff56433a4))
+
+##### Macros
+
+* **crate_description!:** Uses the `Cargo.toml` description field to fill in the `App::about` method at compile time ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778))
+* **crate_name!:** Uses the `Cargo.toml` name field to fill in the `App::new` method at compile time ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778))
+* **app_from_crate!:** Combines `crate_version!`, `crate_name!`, `crate_description!`, and `crate_authors!` into a single macro call to build a default `App` instance from the `Cargo.toml` fields ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778))
+
+
+#### Features
+
+* **no_cargo:** adds a `no_cargo` feature to disable Cargo-env-var-dependent macros for those *not* using `cargo` to build their crates (#786) ([6fdd2f9d](https://github.com/kbknapp/clap-rs/commit/6fdd2f9d693aaf1118fc61bd362273950703f43d))
+
+#### Bug Fixes
+
+* **Options:** fixes a critical bug where options weren't forced to have a value ([5a5f2b1e](https://github.com/kbknapp/clap-rs/commit/5a5f2b1e9f598a0d0280ef3e98abbbba2bc41132), closes [#665](https://github.com/kbknapp/clap-rs/issues/665))
+* fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands ([d3d34a2b](https://github.com/kbknapp/clap-rs/commit/d3d34a2b51ef31004055b0ab574f766d801c3adf), closes [#789](https://github.com/kbknapp/clap-rs/issues/789))
+* **Help Subcommand:** fixes a bug where the help subcommand couldn't be overriden ([d34ec3e0](https://github.com/kbknapp/clap-rs/commit/d34ec3e032d03e402d8e87af9b2942fe2819b2da), closes [#787](https://github.com/kbknapp/clap-rs/issues/787))
+* **Low Index Multiples:** fixes a bug which caused combinations of LowIndexMultiples and `Arg::allow_hyphen_values` to fail parsing ([26c670ca](https://github.com/kbknapp/clap-rs/commit/26c670ca16d2c80dc26d5c1ce83380ace6357318))
+
+#### Improvements
+
+* **Default Values:** improves the error message when default values are involved ([1f33de54](https://github.com/kbknapp/clap-rs/commit/1f33de545036e7fd2f80faba251fca009bd519b8), closes [#774](https://github.com/kbknapp/clap-rs/issues/774))
+* **YAML:** adds conditional requirements and conditional default values to YAML ([9a4df327](https://github.com/kbknapp/clap-rs/commit/9a4df327893486adb5558ffefba790c634ccdc6e), closes [#764](https://github.com/kbknapp/clap-rs/issues/764))
+* Support `--("some-arg-name")` syntax for defining long arg names when using `clap_app!` macro ([f41ec962](https://github.com/kbknapp/clap-rs/commit/f41ec962c243a5ffff8b1be1ae2ad63970d3d1d4))
+* Support `("some app name")` syntax for defining app names when using `clap_app!` macro ([9895b671](https://github.com/kbknapp/clap-rs/commit/9895b671cff784f35cf56abcd8270f7c2ba09699), closes [#759](https://github.com/kbknapp/clap-rs/issues/759))
+* **Help Wrapping:** long app names (with spaces), authors, and descriptions are now wrapped appropriately ([ad4691b7](https://github.com/kbknapp/clap-rs/commit/ad4691b71a63e951ace346318238d8834e04ad8a), closes [#777](https://github.com/kbknapp/clap-rs/issues/777))
+
+
+#### Documentation
+
+* **Conditional Default Values:** fixes the failing doc tests of Arg::default_value_ifs ([4ef09101](https://github.com/kbknapp/clap-rs/commit/4ef091019c083b4db1a0c13f1c1e95ac363259f2))
+* **Conditional Requirements:** adds docs for Arg::requires_ifs ([7f296e29](https://github.com/kbknapp/clap-rs/commit/7f296e29db7d9036e76e5dbcc9c8b20dfe7b25bd))
+* **README.md:** fix some typos ([f22c21b4](https://github.com/kbknapp/clap-rs/commit/f22c21b422d5b287d1a1ac183a379ee02eebf54f))
+* **src/app/mod.rs:** fix some typos ([5c9b0d47](https://github.com/kbknapp/clap-rs/commit/5c9b0d47ca78dea285c5b9dec79063d24c3e451a))
+
+<a name="v2.19.3"></a>
+### v2.19.3 (2016-12-28)
+
+
+#### Bug Fixes
+
+* fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands ([a0ee4993](https://github.com/kbknapp/clap-rs/commit/a0ee4993015ea97b06b5bc9f378d8bcb18f1c51c), closes [#789](https://github.com/kbknapp/clap-rs/issues/789))
+
+
+
+<a name="v2.19.2"></a>
+### v2.19.2 (2016-12-08)
+
+#### Bug Fixes
+
+* **ZSH Completions:** escapes square brackets in ZSH completions ([7e17d5a3](https://github.com/kbknapp/clap-rs/commit/7e17d5a36b2cc2cc77e7b15796b14d639ed3cbf7), closes [#771](https://github.com/kbknapp/clap-rs/issues/771))
+
+#### Documentation
+
+* **Examples:** adds subcommand examples ([0e0f3354](https://github.com/kbknapp/clap-rs/commit/0e0f33547a6901425afc1d9fbe19f7ae3832d9a4), closes [#766](https://github.com/kbknapp/clap-rs/issues/766))
+* **README.md:** adds guidance on when to use ~ in version pinning, and clarifies breaking change policy ([591eaefc](https://github.com/kbknapp/clap-rs/commit/591eaefc7319142ba921130e502bb0729feed907), closes [#765](https://github.com/kbknapp/clap-rs/issues/765))
+
+
+
+<a name="v2.19.1"></a>
+### v2.19.1 (2016-12-01)
+
+
+#### Bug Fixes
+
+* **Help Messages:** fixes help message alignment when specific settings are used on options ([cd94b318](https://github.com/kbknapp/clap-rs/commit/cd94b3188d63b63295a319e90e826bca46befcd2), closes [#760](https://github.com/kbknapp/clap-rs/issues/760))
+
+#### Improvements
+
+* **Bash Completion:** allows bash completion to fall back to traidtional bash completion upon no matching completing function ([b1b16d56](https://github.com/kbknapp/clap-rs/commit/b1b16d56d8fddf819bdbe24b3724bb6a9f3fa613)))
+
+
+<a name="v2.19.0"></a>
+## v2.19.0 (2016-11-21)
+
+#### Features
+
+* allows specifying AllowLeadingHyphen style values, but only for specific args vice command wide ([c0d70feb](https://github.com/kbknapp/clap-rs/commit/c0d70febad9996a77a54107054daf1914c50d4ef), closes [#742](https://github.com/kbknapp/clap-rs/issues/742))
+
+#### Bug Fixes
+
+* **Required Unless:** fixes a bug where having required_unless set doesn't work when conflicts are also set ([d20331b6](https://github.com/kbknapp/clap-rs/commit/d20331b6f7940ac3a4e919999f8bb4780875125d), closes [#753](https://github.com/kbknapp/clap-rs/issues/753))
+* **ZSH Completions:** fixes an issue where zsh completions caused panics if there were no subcommands ([49e7cdab](https://github.com/kbknapp/clap-rs/commit/49e7cdab76dd1ccc07221e360f07808ec62648aa), closes [#754](https://github.com/kbknapp/clap-rs/issues/754))
+
+#### Improvements
+
+* **Validators:** improves the error messages for validators ([65eb3385](https://github.com/kbknapp/clap-rs/commit/65eb33859d3ff53e7d3277f02a9d3fd9038a9dfb), closes [#744](https://github.com/kbknapp/clap-rs/issues/744))
+
+#### Documentation
+
+* updates the docs landing page ([01e1e33f](https://github.com/kbknapp/clap-rs/commit/01e1e33f377934099a4a725fab5cd6c5ff50eaa2))
+* adds the macro version back to the readme ([45eb9bf1](https://github.com/kbknapp/clap-rs/commit/45eb9bf130329c3f3853aba0342c2fe3c64ff80f))
+* fix broken docs links ([808e7cee](https://github.com/kbknapp/clap-rs/commit/808e7ceeb86d4a319bdc270f51c23a64621dbfb3))
+* **Compatibility Policy:** adds an official compatibility policy to ([760d66dc](https://github.com/kbknapp/clap-rs/commit/760d66dc17310b357f257776624151da933cd25d), closes [#740](https://github.com/kbknapp/clap-rs/issues/740))
+* **Contributing:** updates the readme to improve the readability and contributing sections ([eb51316c](https://github.com/kbknapp/clap-rs/commit/eb51316cdfdc7258d287ba13b67ef2f42bd2b8f6))
+
+<a name="v2.18.0"></a>
+## v2.18.0 (2016-11-05)
+
+
+#### Features
+
+* **Completions:** adds completion support for PowerShell. ([cff82c88](https://github.com/kbknapp/clap-rs/commit/cff82c880e21064fca63351507b80350df6caadf), closes [#729](https://github.com/kbknapp/clap-rs/issues/729))
+
+
+
+<a name="v2.17.1"></a>
+### v2.17.1 (2016-11-02)
+
+
+#### Bug Fixes
+
+* **Low Index Multiples:** fixes a bug where using low index multiples was propagated to subcommands ([33924e88](https://github.com/kbknapp/clap-rs/commit/33924e884461983c4e6b5ea1330fecc769a4ade7), closes [#725](https://github.com/kbknapp/clap-rs/issues/725))
+
+
+
+<a name="v2.17.0"></a>
+## v2.17.0 (2016-11-01)
+
+
+#### Features
+
+* **Positional Args:** allows specifying the second to last positional argument as multiple(true) ([1ced2a74](https://github.com/kbknapp/clap-rs/commit/1ced2a7433ea8937a1b260ea65d708f32ca7c95e), closes [#725](https://github.com/kbknapp/clap-rs/issues/725))
+
+
+
+<a name="v2.16.4"></a>
+### v2.16.4 (2016-10-31)
+
+
+#### Improvements
+
+* **Error Output:** conflicting errors are now symetrical, meaning more consistent and less confusing ([3d37001d](https://github.com/kbknapp/clap-rs/commit/3d37001d1dc647d73cc597ff172f1072d4beb80d), closes [#718](https://github.com/kbknapp/clap-rs/issues/718))
+
+#### Documentation
+
+* Fix typo in example `13a_enum_values_automatic` ([c22fbc07](https://github.com/kbknapp/clap-rs/commit/c22fbc07356e556ffb5d1a79ec04597d149b915e))
+* **README.md:** fixes failing yaml example (#715) ([21fba9e6](https://github.com/kbknapp/clap-rs/commit/21fba9e6cd8c163012999cd0ce271ec8780c5695))
+
+#### Bug Fixes
+
+* **ZSH Completions:** fixes bug that caused panic on subcommands with aliases ([5c70e1a0](https://github.com/kbknapp/clap-rs/commit/5c70e1a01bc977e44c10015d18bb8e215c32dfc8), closes [#714](https://github.com/kbknapp/clap-rs/issues/714))
+* **debug:** fixes the debug feature (#716) ([6c11ccf4](https://github.com/kbknapp/clap-rs/commit/6c11ccf443d46258d51f7cda33fbcc81e7fe8e90))
+
+
+
+<a name="v2.16.3"></a>
+### v2.16.3 (2016-10-28)
+
+
+#### Bug Fixes
+
+* Derive display order after propagation ([9cb6facf](https://github.com/kbknapp/clap-rs/commit/9cb6facf507aff7cddd124b8c29714d2b0e7bd13), closes [#706](https://github.com/kbknapp/clap-rs/issues/706))
+* **yaml-example:** inconsistent args ([847f7199](https://github.com/kbknapp/clap-rs/commit/847f7199219ead5065561d91d64780d99ae4b587))
+
+
+
+<a name="v2.15.1"></a>
+### v2.16.2 (2016-10-25)
+
+
+#### Bug Fixes
+
+* **Fish Completions:** fixes a bug where single quotes are not escaped ([780b4a18](https://github.com/kbknapp/clap-rs/commit/780b4a18281b6f7f7071e1b9db2290fae653c406), closes [#704](https://github.com/kbknapp/clap-rs/issues/704))
+
+
+<a name="v2.16.1"></a>
+### v2.16.1 (2016-10-24)
+
+
+#### Bug Fixes
+
+* **Help Message:** fixes a regression bug where args with multiple(true) threw off alignment ([ebddac79](https://github.com/kbknapp/clap-rs/commit/ebddac791f3ceac193d5ad833b4b734b9643a7af), closes [#702](https://github.com/kbknapp/clap-rs/issues/702))
+
+
+
+<a name="v2.16.0"></a>
+## v2.16.0 (2016-10-23)
+
+
+#### Features
+
+* **Completions:** adds ZSH completion support ([3e36b0ba](https://github.com/kbknapp/clap-rs/commit/3e36b0bac491d3f6194aee14604caf7be26b3d56), closes [#699](https://github.com/kbknapp/clap-rs/issues/699))
+
+
+
+<a name="v2.15.0"></a>
+## v2.15.0 (2016-10-21)
+
+
+#### Features
+
+* **AppSettings:** adds new setting `AppSettings::AllowNegativeNumbers` ([ab064546](https://github.com/kbknapp/clap-rs/commit/ab06454677fb6aa9b9f804644fcca2168b1eaee3), closes [#696](https://github.com/kbknapp/clap-rs/issues/696))
+
+#### Documentation
+
+* **app/settings.rs:** moves variants to roughly alphabetical order ([9ed4d4d7](https://github.com/kbknapp/clap-rs/commit/9ed4d4d7957a23357aef60081e45639ab9e3905f))
+
+
+<a name="v2.14.1"></a>
+### v2.14.1 (2016-10-20)
+
+
+#### Documentation
+
+* Improve documentation around features ([4ee85b95](https://github.com/kbknapp/clap-rs/commit/4ee85b95d2d16708a016a3ba4e6e2c93b89b7fad))
+* reword docs for ErrorKind and app::Settings ([3ccde7a4](https://github.com/kbknapp/clap-rs/commit/3ccde7a4b8f7a2ea8b916a5415c04a8ff4b5cb7a))
+* fix tests that fail when the "suggestions" feature is disabled ([996fc381](https://github.com/kbknapp/clap-rs/commit/996fc381763a48d125c7ea8a58fed057fd0b4ac6))
+* fix the OsString-using doc-tests ([af9e1a39](https://github.com/kbknapp/clap-rs/commit/af9e1a393ce6cdda46a03c8a4f48df222b015a24))
+* tag non-rust code blocks as such instead of ignoring them ([0ba9f4b1](https://github.com/kbknapp/clap-rs/commit/0ba9f4b123f281952581b6dec948f7e51dd22890))
+* **ErrorKind:** improve some errors about subcommands ([9f6217a4](https://github.com/kbknapp/clap-rs/commit/9f6217a424da823343d7b801b9c350dee3cd1906))
+* **yaml:** make sure the doc-tests don't fail before "missing file" ([8c0f5551](https://github.com/kbknapp/clap-rs/commit/8c0f55516f4910c78c9f8a2bdbd822729574f95b))
+
+#### Improvements
+
+* Stabilize clap_app! ([cd516006](https://github.com/kbknapp/clap-rs/commit/cd516006e35c37b005f329338560a0a53d1f3e00))
+* **with_defaults:** Deprecate App::with_defaults() ([26085409](https://github.com/kbknapp/clap-rs/commit/2608540940c8bb66e517b65706bc7dea55510682), closes [#638](https://github.com/kbknapp/clap-rs/issues/638))
+
+#### Bug Fixes
+
+* fixes a bug that made determining when to auto-wrap long help messages inconsistent ([468baadb](https://github.com/kbknapp/clap-rs/commit/468baadb8398fc1d37897b0c49374aef4cf97dca), closes [#688](https://github.com/kbknapp/clap-rs/issues/688))
+* **Completions:** fish completions for nested subcommands ([a61eaf8a](https://github.com/kbknapp/clap-rs/commit/a61eaf8aade76cfe90ccc0f7125751ebf60e3254))
+* **features:** Make lints not enable other nightly-requiring features ([835f75e3](https://github.com/kbknapp/clap-rs/commit/835f75e3ba20999117363ed9f916464d777f36ef))
+
+
+
+<a name="v2.14.0"></a>
+## v2.14.0 (2016-10-05)
+
+
+#### Features
+
+* **arg_aliases:** Ability to alias arguments ([33b5f6ef](https://github.com/kbknapp/clap-rs/commit/33b5f6ef2c9612ecabb31f96b824793e46bfd3dd), closes [#669](https://github.com/kbknapp/clap-rs/issues/669))
+* **flag_aliases:** Ability to alias flags ([40d6dac9](https://github.com/kbknapp/clap-rs/commit/40d6dac973927dded6ab423481634ef47ee7bfd7))
+
+#### Bug Fixes
+
+* **UsageParser:** Handle non-ascii names / options. ([1d6a7c6e](https://github.com/kbknapp/clap-rs/commit/1d6a7c6e7e6aadc527346aa822f19d8587f714f3), closes [#664](https://github.com/kbknapp/clap-rs/issues/664))
+
+#### Documentation
+
+* typo ([bac417fa](https://github.com/kbknapp/clap-rs/commit/bac417fa1cea3d32308334c7cccfcf54546cd9d8))
+
+
+<a name="v2.13.0"></a>
+## v2.13.0 (2016-09-18)
+
+
+#### Documentation
+
+* updates README.md with new website information and updated video tutorials info ([0c19c580](https://github.com/kbknapp/clap-rs/commit/0c19c580cf50f1b82ff32f70b36708ae2bcac132))
+* updates the docs about removing implicit value_delimiter(true) ([c81bc722](https://github.com/kbknapp/clap-rs/commit/c81bc722ebb8a86d22be89b5aec98df9fe222a08))
+* **Default Values:** adds better examples on using default values ([57a8d9ab](https://github.com/kbknapp/clap-rs/commit/57a8d9abb2f973c235a8a14f8fc031673d7a7460), closes [#418](https://github.com/kbknapp/clap-rs/issues/418))
+
+#### Bug Fixes
+
+* **Value Delimiters:** fixes the confusion around implicitly setting value delimiters. (default is now `false`) ([09d4d0a9](https://github.com/kbknapp/clap-rs/commit/09d4d0a9038d7ce2df55c2aec95e16f36189fcee), closes [#666](https://github.com/kbknapp/clap-rs/issues/666))
+
+
+
+<a name="v2.12.1"></a>
+### v2.12.1 (2016-09-13)
+
+
+#### Bug Fixes
+
+* **Help Wrapping:** fixes a regression-bug where the old {n} newline char stopped working ([92ac353b](https://github.com/kbknapp/clap-rs/commit/92ac353b48b7caa2511ad2a046d94da93c236cf6), closes [#661](https://github.com/kbknapp/clap-rs/issues/661))
+
+
+
+<a name="v2.12.0"></a>
+## v2.12.0 (2016-09-13)
+
+
+#### Features
+
+* **Help:** adds ability to hide the possible values on a per argument basis ([9151ef73](https://github.com/kbknapp/clap-rs/commit/9151ef739871f2e74910c342299c0de196b95dec), closes [#640](https://github.com/kbknapp/clap-rs/issues/640))
+* **help:** allow for limiting detected terminal width ([a43e28af](https://github.com/kbknapp/clap-rs/commit/a43e28af85c9a9deaedd5ef735f4f13008daab29), closes [#653](https://github.com/kbknapp/clap-rs/issues/653))
+
+#### Documentation
+
+* **Help Wrapping:** removes the verbiage about using `'{n}'` to insert newlines in help text ([c5a2b352](https://github.com/kbknapp/clap-rs/commit/c5a2b352ca600f5b802290ad945731066cd53611))
+* **Value Delimiters:** updates the docs for the Arg::multiple method WRT value delimiters and default settings ([f9d17a06](https://github.com/kbknapp/clap-rs/commit/f9d17a060aa53f10d0a6e1a7eed5d989d1a59533))
+* **appsettings:** Document AppSetting::DisableVersion ([94501965](https://github.com/kbknapp/clap-rs/commit/945019654d2ca67eb2b1d6014fdf80b84d528d30), closes [#589](https://github.com/kbknapp/clap-rs/issues/589))
+
+#### Bug Fixes
+
+* **AllowLeadingHyphen:** fixes a bug where valid args aren't recognized with this setting ([a9699e4d](https://github.com/kbknapp/clap-rs/commit/a9699e4d7cdc9a06e73b845933ff1fe6d76f016a), closes [#588](https://github.com/kbknapp/clap-rs/issues/588))
+
+#### Improvements
+
+* **Help Wrapping:**
+ * clap now ignores hard newlines in help messages and properly re-aligns text, but still wraps if the term width is too small ([c7678523](https://github.com/kbknapp/clap-rs/commit/c76785239fd42adc8ca04f9202b6fec615aa9f14), closes [#617](https://github.com/kbknapp/clap-rs/issues/617))
+ * makes some minor changes to when next line help is automatically used ([01cae799](https://github.com/kbknapp/clap-rs/commit/01cae7990a33167ac35103fb36c811b4fe6eb98f))
+* **Value Delimiters:** changes the default value delimiter rules ([f9e69254](https://github.com/kbknapp/clap-rs/commit/f9e692548e8c94de15f909432de301407d6bb834), closes [#655](https://github.com/kbknapp/clap-rs/issues/655))
+* **YAML:** supports setting Arg::require_delimiter from YAML ([b9b55a39](https://github.com/kbknapp/clap-rs/commit/b9b55a39dfebcdbdc05dca2692927e503db50816))
+
+#### Performance
+
+* **help:** fix redundant contains() checks ([a8afed74](https://github.com/kbknapp/clap-rs/commit/a8afed7428bf0733f8e93bb11ad6c00d9e970fcc))
+
+
+
+<a name="v2.11.3"></a>
+### v2.11.3 (2016-09-07)
+
+
+#### Documentation
+
+* **Help Wrapping:** removes the verbiage about using `'{n}'` to insert newlines in help text ([c5a2b352](https://github.com/kbknapp/clap-rs/commit/c5a2b352ca600f5b802290ad945731066cd53611))
+
+#### Improvements
+
+* **Help Wrapping:**
+ * clap now ignores hard newlines in help messages and properly re-aligns text, but still wraps if the term width is too small ([c7678523](https://github.com/kbknapp/clap-rs/commit/c76785239fd42adc8ca04f9202b6fec615aa9f14), closes [#617](https://github.com/kbknapp/clap-rs/issues/617))
+ * makes some minor changes to when next line help is automatically used ([01cae799](https://github.com/kbknapp/clap-rs/commit/01cae7990a33167ac35103fb36c811b4fe6eb98f))
+* **YAML:** supports setting Arg::require_delimiter from YAML ([b9b55a39](https://github.com/kbknapp/clap-rs/commit/b9b55a39dfebcdbdc05dca2692927e503db50816))
+
+
+
+
+<a name="v2.11.2"></a>
+### v2.11.2 (2016-09-06)
+
+#### Improvements
+
+* **Help Wrapping:** makes some minor changes to when next line help is automatically used ([5658b117](https://github.com/kbknapp/clap-rs/commit/5658b117aec3e03adff9c8c52a4c4bc1fcb4e1ff))
+
+
+<a name="v2.11.1"></a>
+### v2.11.1 (2016-09-05)
+
+
+#### Bug Fixes
+
+* **Settings:** fixes an issue where settings weren't propogated down through grand-child subcommands ([b3efc107](https://github.com/kbknapp/clap-rs/commit/b3efc107515d78517b20798ff3890b8a2b04498e), closes [#638](https://github.com/kbknapp/clap-rs/issues/638))
+
+#### Features
+
+* **Errors:** Errors with custom description ([58512f2f](https://github.com/kbknapp/clap-rs/commit/58512f2fcb430745f1ee6ee8f1c67f62dc216c73))
+
+#### Improvements
+
+* **help:** use term_size instead of home-grown solution ([fc7327e9](https://github.com/kbknapp/clap-rs/commit/fc7327e9dcf4258ef2baebf0a8714d9c0622855b))
+
+
+
+<a name="v2.11.0"></a>
+### v2.11.0 (2016-08-28)
+
+
+#### Bug Fixes
+
+* **Groups:** fixes some usage strings that contain both args in groups and ones that conflict with each other ([3d782def](https://github.com/kbknapp/clap-rs/commit/3d782def57725e2de26ca5a5bc5cc2e40ddebefb), closes [#616](https://github.com/kbknapp/clap-rs/issues/616))
+
+#### Documentation
+
+* moves docs to docs.rs ([03209d5e](https://github.com/kbknapp/clap-rs/commit/03209d5e1300906f00bafec1869c2047a92e5071), closes [#634](https://github.com/kbknapp/clap-rs/issues/634))
+
+#### Improvements
+
+* **Completions:** uses standard conventions for bash completion files, namely '{bin}.bash-completion' ([27f5bbfb](https://github.com/kbknapp/clap-rs/commit/27f5bbfbcc9474c2f57c2b92b1feb898ae46ee70), closes [#567](https://github.com/kbknapp/clap-rs/issues/567))
+* **Help:** automatically moves help text to the next line and wraps when term width is determined to be too small, or help text is too long ([150964c4](https://github.com/kbknapp/clap-rs/commit/150964c4e7124d54476c9d9b4b3f2406f0fd00e5), closes [#597](https://github.com/kbknapp/clap-rs/issues/597))
+* **YAML Errors:** vastly improves error messages when using YAML ([f43b7c65](https://github.com/kbknapp/clap-rs/commit/f43b7c65941c53adc0616b8646a21dc255862eb2), closes [#574](https://github.com/kbknapp/clap-rs/issues/574))
+
+#### Features
+
+* adds App::with_defaults to automatically use crate_authors! and crate_version! macros ([5520bb01](https://github.com/kbknapp/clap-rs/commit/5520bb012c127dfd299fd55699443c744d8dcd5b), closes [#600](https://github.com/kbknapp/clap-rs/issues/600))
+
+
+
+<a name="v2.10.4"></a>
+### v2.10.4 (2016-08-25)
+
+
+#### Bug Fixes
+
+* **Help Wrapping:** fixes a bug where help is wrapped incorrectly and causing a panic with some non-English characters ([d0b442c7](https://github.com/kbknapp/clap-rs/commit/d0b442c7beeecac9764406bc3bd171ced0b8825e), closes [#626](https://github.com/kbknapp/clap-rs/issues/626))
+
+
+
+<a name="v2.10.3"></a>
+### v2.10.3 (2016-08-25)
+
+#### Features
+
+* **Help:** adds new short hand way to use source formatting and ignore term width in help messages ([7dfdaf20](https://github.com/kbknapp/clap-rs/commit/7dfdaf200ebb5c431351a045b48f5e0f0d3f31db), closes [#625](https://github.com/kbknapp/clap-rs/issues/625))
+
+#### Documentation
+
+* **Term Width:** adds details about set_term_width(0) ([00b8205d](https://github.com/kbknapp/clap-rs/commit/00b8205d22639d1b54b9c453c55c785aace52cb2))
+
+#### Bug Fixes
+
+* **Unicode:** fixes two bugs where non-English characters were stripped or caused a panic with help wrapping ([763a5c92](https://github.com/kbknapp/clap-rs/commit/763a5c920e23efc74d190af0cb8b5dd714b2d67a), closes [#626](https://github.com/kbknapp/clap-rs/issues/626))
+
+
+
+<a name="v2.10.2"></a>
+### v2.10.2 (2016-08-22)
+
+
+#### Bug Fixes
+
+* fixes a bug where the help is printed twice ([a643fb28](https://github.com/kbknapp/clap-rs/commit/a643fb283acd9905dc727c4579c5c9fa2ceaa7e7), closes [#623](https://github.com/kbknapp/clap-rs/issues/623))
+
+
+
+<a name="v2.10.1"></a>
+### v2.10.1 (2016-08-21)
+
+
+#### Bug Fixes
+
+* **Help Subcommand:** fixes misleading usage string when using multi-level subcommmands ([e203515e](https://github.com/kbknapp/clap-rs/commit/e203515e3ac495b405dbba4f78fb6af148fd282e), closes [#618](https://github.com/kbknapp/clap-rs/issues/618))
+
+#### Features
+
+* **YAML:** allows using lists or single values with arg declarations ([9ade2cd4](https://github.com/kbknapp/clap-rs/commit/9ade2cd4b268d6d7fe828319ce6a523c641b9c38), closes [#614](https://github.com/kbknapp/clap-rs/issues/614), [#613](https://github.com/kbknapp/clap-rs/issues/613))
+
+
+
+<a name="v2.10.0"></a>
+## v2.10.0 (2016-07-29)
+
+
+#### Features
+
+* **Completions:** one can generate a basic fish completions script at compile time ([1979d2f2](https://github.com/kbknapp/clap-rs/commit/1979d2f2f3216e57d02a97e624a8a8f6cf867ed9))
+
+#### Bug Fixes
+
+* **parser:** preserve external subcommand name ([875df243](https://github.com/kbknapp/clap-rs/commit/875df24316c266920a073c13bbefbf546bc1f635))
+
+#### Breaking Changes
+
+* **parser:** preserve external subcommand name ([875df243](https://github.com/kbknapp/clap-rs/commit/875df24316c266920a073c13bbefbf546bc1f635))
+
+#### Documentation
+
+* **YAML:** fixes example 17's incorrect reference to arg_groups instead of groups ([b6c99e13](https://github.com/kbknapp/clap-rs/commit/b6c99e1377f918e78c16c8faced70a71607da931), closes [#601](https://github.com/kbknapp/clap-rs/issues/601))
+
+
+
+<a name="2.9.3"></a>
+### 2.9.3 (2016-07-24)
+
+
+#### Bug Fixes
+
+* fixes bug where only first arg in list of required_unless_one is recognized ([1fc3b55b](https://github.com/kbknapp/clap-rs/commit/1fc3b55bd6c8653b02e7c4253749c6b77737d2ac), closes [#575](https://github.com/kbknapp/clap-rs/issues/575))
+* **Settings:** fixes typo subcommandsrequired->subcommandrequired ([fc72cdf5](https://github.com/kbknapp/clap-rs/commit/fc72cdf591d30f5d9375d0b5cc2a2ff3e812f9f6), closes [#593](https://github.com/kbknapp/clap-rs/issues/593))
+
+#### Features
+
+* **Completions:** adds the ability to generate completions to io::Write object ([9f62cf73](https://github.com/kbknapp/clap-rs/commit/9f62cf7378ba5acb5ce8c5bac89b4aa60c30755f))
+* **Settings:** Add unset_setting and unset_settings fns to App (#598) ([0ceba231](https://github.com/kbknapp/clap-rs/commit/0ceba231c6767cd6d88fdb1feeeea41deadf77ff), closes [#590](https://github.com/kbknapp/clap-rs/issues/590))
+
+
+<a name="2.9.2"></a>
+### 2.9.2 (2016-07-03)
+
+
+#### Documentation
+
+* **Completions:** fixes the formatting of the Cargo.toml excerpt in the completions example ([722f2607](https://github.com/kbknapp/clap-rs/commit/722f2607beaef56b6a0e433db5fd09492d9f028c))
+
+#### Bug Fixes
+
+* **Completions:** fixes bug where --help and --version short weren't added to the completion list ([e9f2438e](https://github.com/kbknapp/clap-rs/commit/e9f2438e2ce99af0ae570a2eaf541fc7f55b771b), closes [#536](https://github.com/kbknapp/clap-rs/issues/536))
+
+
+
+<a name="2.9.1"></a>
+### 2.9.1 (2016-07-02)
+
+
+#### Improvements
+
+* **Completions:** allows multiple completions to be built by namespacing with bin name ([57484b2d](https://github.com/kbknapp/clap-rs/commit/57484b2daeaac01c1026e8c84efc8bf099e0eb31))
+
+
+<a name="v2.9.0"></a>
+## v2.9.0 (2016-07-01)
+
+
+#### Documentation
+
+* **Completions:**
+ * fixes some errors in the completion docs ([9b359bf0](https://github.com/kbknapp/clap-rs/commit/9b359bf06255d3dad8f489308044b60a9d1e6a87))
+ * adds documentation for completion scripts ([c6c519e4](https://github.com/kbknapp/clap-rs/commit/c6c519e40efd6c4533a9ef5efe8e74fd150391b7))
+
+#### Features
+
+* **Completions:**
+ * one can now generate a bash completions script at compile time! ([e75b6c7b](https://github.com/kbknapp/clap-rs/commit/e75b6c7b75f729afb9eb1d2a2faf61dca7674634), closes [#376](https://github.com/kbknapp/clap-rs/issues/376))
+ * completions now include aliases to subcommands, including all subcommand options ([0ab9f840](https://github.com/kbknapp/clap-rs/commit/0ab9f84052a8cf65b5551657f46c0c270841e634), closes [#556](https://github.com/kbknapp/clap-rs/issues/556))
+ * completions now continue completing even after first completion ([18fc2e5b](https://github.com/kbknapp/clap-rs/commit/18fc2e5b5af63bf54a94b72cec5e1223d49f4806))
+ * allows matching on possible values in options ([89cc2026](https://github.com/kbknapp/clap-rs/commit/89cc2026ba9ac69cf44c5254360bbf99236d4f89), closes [#557](https://github.com/kbknapp/clap-rs/issues/557))
+
+#### Bug Fixes
+
+* **AllowLeadingHyphen:** fixes an issue where isn't ignored like it should be with this setting ([96c24c9a](https://github.com/kbknapp/clap-rs/commit/96c24c9a8fa1f85e06138d3cdd133e51659e19d2), closes [#558](https://github.com/kbknapp/clap-rs/issues/558))
+
+<a name="v2.8.0"></a>
+## v2.8.0 (2016-06-30)
+
+
+#### Features
+
+* **Arg:** adds new setting `Arg::require_delimiter` which requires val delimiter to parse multiple values ([920b5595](https://github.com/kbknapp/clap-rs/commit/920b5595ed72abfb501ce054ab536067d8df2a66))
+
+#### Bug Fixes
+
+* Declare term::Winsize as repr(C) ([5d663d90](https://github.com/kbknapp/clap-rs/commit/5d663d905c9829ce6e7a164f1f0896cdd70236dd))
+
+#### Documentation
+
+* **Arg:** adds docs for ([49af4e38](https://github.com/kbknapp/clap-rs/commit/49af4e38a5dae2ab0a7fc3b4147e2c053d532484))
+
+
+
+<a name="v2.7.1"></a>
+### v2.7.1 (2016-06-29)
+
+
+#### Bug Fixes
+
+* **Options:**
+ * options with multiple values and using delimiters no longer parse additional values after a trailing space ([cdc500bd](https://github.com/kbknapp/clap-rs/commit/cdc500bdde6abe238c36ade406ddafc2bafff583))
+ * using options with multiple values and with an = no longer parse args after the trailing space as values ([290f61d0](https://github.com/kbknapp/clap-rs/commit/290f61d07177413cf082ada55526d83405f6d011))
+
+
+
+<a name="v2.7.0"></a>
+## v2.7.0 (2016-06-28)
+
+
+#### Documentation
+
+* fix typos ([43b3d40b](https://github.com/kbknapp/clap-rs/commit/43b3d40b8c38b1571da75af86b5088be96cccec2))
+* **ArgGroup:** vastly improves ArgGroup docs by adding better examples ([9e5f4f5d](https://github.com/kbknapp/clap-rs/commit/9e5f4f5d734d630bca5535c3a0aa4fd4f9db3e39), closes [#534](https://github.com/kbknapp/clap-rs/issues/534))
+
+#### Features
+
+* **ArgGroup:** one can now specify groups which require AT LEAST one of the args ([33689acc](https://github.com/kbknapp/clap-rs/commit/33689acc689b217a8c0ee439f1b1225590c38355), closes [#533](https://github.com/kbknapp/clap-rs/issues/533))
+
+#### Bug Fixes
+
+* **App:** using `App::print_help` now prints the same as would have been printed by `--help` or the like ([e84cc018](https://github.com/kbknapp/clap-rs/commit/e84cc01836bbe0527e97de6db9889bd9e0fd6ba1), closes [#536](https://github.com/kbknapp/clap-rs/issues/536))
+* **Help:**
+ * prevents invoking <cmd> help help and displaying incorrect help message ([e3d2893f](https://github.com/kbknapp/clap-rs/commit/e3d2893f377942a2d4cf3c6ff04524d0346e6fdb), closes [#538](https://github.com/kbknapp/clap-rs/issues/538))
+ * subcommand help messages requested via <cmd> help <sub> now correctly match <cmd> <sub> --help ([08ad1cff](https://github.com/kbknapp/clap-rs/commit/08ad1cff4fec57224ea957a2891a057b323c01bc), closes [#539](https://github.com/kbknapp/clap-rs/issues/539))
+
+#### Improvements
+
+* **ArgGroup:** Add multiple ArgGroups per Arg ([902e182f](https://github.com/kbknapp/clap-rs/commit/902e182f7a58aff11ff01e0a452abcdbdb2262aa), closes [#426](https://github.com/kbknapp/clap-rs/issues/426))
+* **Usage Strings:** `[FLAGS]` and `[ARGS]` are no longer blindly added to usage strings ([9b2e45b1](https://github.com/kbknapp/clap-rs/commit/9b2e45b170aff567b038d8b3368880b6046c10c6), closes [#537](https://github.com/kbknapp/clap-rs/issues/537))
+* **arg_enum!:** allows using meta items like repr(C) with arg_enum!s ([edf9b233](https://github.com/kbknapp/clap-rs/commit/edf9b2331c17a2cbcc13f961add4c55c2778e773), closes [#543](https://github.com/kbknapp/clap-rs/issues/543))
+
+
+
+<a name="v2.6.0"></a>
+## v2.6.0 (2016-06-14)
+
+
+#### Improvements
+
+* removes extra newline from help output ([86e61d19](https://github.com/kbknapp/clap-rs/commit/86e61d19a748fb9870fcf1175308984e51ca1115))
+* allows printing version to any io::Write object ([921f5f79](https://github.com/kbknapp/clap-rs/commit/921f5f7916597f1d028cd4a65bfe76a01c801724))
+* removes extra newline when printing version ([7e2e2cbb](https://github.com/kbknapp/clap-rs/commit/7e2e2cbb4a8a0f050bb8072a376f742fc54b8589))
+* **Aliases:** improves readability of asliases in help messages ([ca511de7](https://github.com/kbknapp/clap-rs/commit/ca511de71f5b8c2ac419f1b188658e8c63b67846), closes [#526](https://github.com/kbknapp/clap-rs/issues/526), [#529](https://github.com/kbknapp/clap-rs/issues/529))
+* **Usage Strings:** improves the default usage string when only a single positional arg is present ([ec86f2da](https://github.com/kbknapp/clap-rs/commit/ec86f2dada1545a63fc72355e22fcdc4c466c215), closes [#518](https://github.com/kbknapp/clap-rs/issues/518))
+
+#### Features
+
+* **Help:** allows wrapping at specified term width (Even on Windows!) ([1761dc0d](https://github.com/kbknapp/clap-rs/commit/1761dc0d27d0d621229d792be40c36fbf65c3014), closes [#451](https://github.com/kbknapp/clap-rs/issues/451))
+* **Settings:**
+ * adds new setting to stop delimiting values with -- or TrailingVarArg ([fc3e0f5a](https://github.com/kbknapp/clap-rs/commit/fc3e0f5afda6d24cdb3c4676614beebe13e1e870), closes [#511](https://github.com/kbknapp/clap-rs/issues/511))
+ * one can now set an AppSetting which is propogated down through child subcommands ([e2341835](https://github.com/kbknapp/clap-rs/commit/e23418351a3b98bf08dfd7744bc14377c70d59ee), closes [#519](https://github.com/kbknapp/clap-rs/issues/519))
+* **Subcommands:** adds support for visible aliases ([7b10e7f8](https://github.com/kbknapp/clap-rs/commit/7b10e7f8937a07fdb8d16a6d8df79ce78d080cd3), closes [#522](https://github.com/kbknapp/clap-rs/issues/522))
+
+#### Bug Fixes
+
+* fixes bug where args are printed out of order with templates ([05abb534](https://github.com/kbknapp/clap-rs/commit/05abb534864764102031a0d402e64ac65867aa87))
+* fixes bug where one can't override version or help flags ([90d7d6a2](https://github.com/kbknapp/clap-rs/commit/90d7d6a2ea8240122dd9bf8d82d3c4f5ebb5c703), closes [#514](https://github.com/kbknapp/clap-rs/issues/514))
+* fixes issue where before_help wasn't printed ([b3faff60](https://github.com/kbknapp/clap-rs/commit/b3faff6030f76a23f26afcfa6a90169002ed7106))
+* **Help:** `App::before_help` and `App::after_help` now correctly wrap ([1f4da767](https://github.com/kbknapp/clap-rs/commit/1f4da7676e6e71aa8dda799f3eeefad105a47819), closes [#516](https://github.com/kbknapp/clap-rs/issues/516))
+* **Settings:** fixes bug where new color settings couldn't be converted from strs ([706a7c11](https://github.com/kbknapp/clap-rs/commit/706a7c11b0900be594de6d5a3121938eff197602))
+* **Subcommands:** subcommands with aliases now display help of the aliased subcommand ([5354d14b](https://github.com/kbknapp/clap-rs/commit/5354d14b51f189885ba110e01e6b76cca3752992), closes [#521](https://github.com/kbknapp/clap-rs/issues/521))
+* **Windows:** fixes a failing windows build ([01e7dfd6](https://github.com/kbknapp/clap-rs/commit/01e7dfd6c07228c0be6695b3c7bf9370d82860d4))
+* **YAML:** adds missing YAML methods for App and Arg ([e468faf3](https://github.com/kbknapp/clap-rs/commit/e468faf3f05950fd9f72d84b69aa2061e91c6c64), closes [#528](https://github.com/kbknapp/clap-rs/issues/528))
+
+
+
+<a name="v2.5.2"></a>
+### v2.5.2 (2016-05-31)
+
+
+#### Improvements
+
+* removes extra newline from help output ([86e61d19](https://github.com/kbknapp/clap-rs/commit/86e61d19a748fb9870fcf1175308984e51ca1115))
+* allows printing version to any io::Write object ([921f5f79](https://github.com/kbknapp/clap-rs/commit/921f5f7916597f1d028cd4a65bfe76a01c801724))
+* removes extra newline when printing version ([7e2e2cbb](https://github.com/kbknapp/clap-rs/commit/7e2e2cbb4a8a0f050bb8072a376f742fc54b8589))
+
+#### Bug Fixes
+
+* fixes bug where args are printed out of order with templates ([3935431d](https://github.com/kbknapp/clap-rs/commit/3935431d5633f577c0826ae2142794b301f4b8ca))
+* fixes bug where one can't override version or help flags ([90d7d6a2](https://github.com/kbknapp/clap-rs/commit/90d7d6a2ea8240122dd9bf8d82d3c4f5ebb5c703), closes [#514](https://github.com/kbknapp/clap-rs/issues/514))
+* fixes issue where before_help wasn't printed ([b3faff60](https://github.com/kbknapp/clap-rs/commit/b3faff6030f76a23f26afcfa6a90169002ed7106))
+
+#### Documentation
+
+* inter-links all types and pages ([3312893d](https://github.com/kbknapp/clap-rs/commit/3312893ddaef3f44d68d8d26ed3d08010be50d97), closes [#505](https://github.com/kbknapp/clap-rs/issues/505))
+* makes all publicly available types viewable in docs ([52ca6505](https://github.com/kbknapp/clap-rs/commit/52ca6505b4fec7b5c2d53d160c072d395eb21da6))
+
+<a name="v2.5.1"></a>
+### v2.5.1 (2016-05-11)
+
+
+#### Bug Fixes
+
+* **Subcommand Aliases**: fixes lifetime issue when setting multiple aliases at once ([ac42f6cf0](https://github.com/kbknapp/clap-rs/commit/ac42f6cf0de6c4920f703807d63061803930b18d))
+
+<a name="v2.5.0"></a>
+## v2.5.0 (2016-05-10)
+
+
+#### Improvements
+
+* **SubCommand Aliases:** adds feature to yaml configs too ([69592195](https://github.com/kbknapp/clap-rs/commit/695921954dde46dfd483399dcdef482c9dd7f34a))
+
+#### Features
+
+* **SubCommands:** adds support for subcommand aliases ([66b4dea6](https://github.com/kbknapp/clap-rs/commit/66b4dea65c44d8f77ff522238a9237aed1bcab6d), closes [#469](https://github.com/kbknapp/clap-rs/issues/469))
+
+
+<a name="v2.4.3"></a>
+### v2.4.3 (2016-05-10)
+
+
+#### Bug Fixes
+
+* **Usage Strings:**
+ * now properly dedups args that are also in groups ([3ca0947c](https://github.com/kbknapp/clap-rs/commit/3ca0947c166b4f8525752255e3a4fa6565eb9689), closes [#498](https://github.com/kbknapp/clap-rs/issues/498))
+ * removes duplicate groups from usage strings ([f574fb8a](https://github.com/kbknapp/clap-rs/commit/f574fb8a7cde4d4a2fa4c4481d59be2d0f135427))
+
+#### Improvements
+
+* **Groups:** formats positional args in groups in a better way ([fef11154](https://github.com/kbknapp/clap-rs/commit/fef11154fb7430d1cbf04a672aabb366e456a368))
+* **Help:**
+ * moves positionals to standard <> formatting ([03dfe5ce](https://github.com/kbknapp/clap-rs/commit/03dfe5ceff1d63f172788ff688567ddad9fe119b))
+ * default help subcommand string has been shortened ([5b7fe8e4](https://github.com/kbknapp/clap-rs/commit/5b7fe8e4161e43ab19e2e5fcf55fbe46791134e9), closes [#494](https://github.com/kbknapp/clap-rs/issues/494))
+
+<a name="v2.4.2"></a>
+### v2.4.3 (2016-05-10)
+
+* Ghost Release
+
+<a name="v2.4.1"></a>
+### v2.4.3 (2016-05-10)
+
+* Ghost Release
+
+<a name="v2.4.0"></a>
+## v2.4.0 (2016-05-02)
+
+
+#### Features
+
+* **Help:** adds support for displaying info before help message ([29fbfa3b](https://github.com/kbknapp/clap-rs/commit/29fbfa3b963f2f3ca7704bf5d3e1201531baa373))
+* **Required:** adds allowing args that are required unless certain args are present ([af1f7916](https://github.com/kbknapp/clap-rs/commit/af1f79168390ea7da4074d0d9777de458ea64971))
+
+#### Documentation
+
+* hides formatting from docs ([cb708093](https://github.com/kbknapp/clap-rs/commit/cb708093a7cd057f08c98b7bd1ed54c2db86ae7e))
+* **required_unless:** adds docs and examples for required_unless ([ca727b52](https://github.com/kbknapp/clap-rs/commit/ca727b52423b9883acd88b2f227b2711bc144573))
+
+#### Bug Fixes
+
+* **Required Args:** fixes issue where missing required args are sometimes duplicatd in error messages ([3beebd81](https://github.com/kbknapp/clap-rs/commit/3beebd81e7bc2faa4115ac109cf570e512c5477f), closes [#492](https://github.com/kbknapp/clap-rs/issues/492))
+
+
+<a name="v2.3.0"></a>
+## v2.3.0 (2016-04-18)
+
+
+#### Improvements
+
+* **macros.rs:** Added write_nspaces macro (a new version of write_spaces) ([9d757e86](https://github.com/kbknapp/clap-rs/commit/9d757e8678e334e5a740ac750c76a9ed4e785cba))
+* **parser.rs:**
+ * Provide a way to create a usage string without the USAGE: title ([a91d378b](https://github.com/kbknapp/clap-rs/commit/a91d378ba0c91b5796457f8c6e881b13226ab735))
+ * Make Parser's create_usage public allowing to have function outside the parser to generate the help ([d51945f8](https://github.com/kbknapp/clap-rs/commit/d51945f8b82ebb0963f4f40b384a9e8335783091))
+ * Expose Parser's flags, opts and positionals argument as iterators ([9b23e7ee](https://github.com/kbknapp/clap-rs/commit/9b23e7ee40e51f7a823644c4496be955dc6c9d3a))
+* **src/args:** Exposes argument display order by introducing a new Trait ([1321630e](https://github.com/kbknapp/clap-rs/commit/1321630ef56955f152c73376d4d85cceb0bb4a12))
+* **srs/args:** Added longest_filter to AnyArg trait ([65b3f667](https://github.com/kbknapp/clap-rs/commit/65b3f667532685f854c699ddd264d326599cf7e5))
+
+#### Features
+
+* **Authors Macro:** adds a crate_authors macro ([38fb59ab](https://github.com/kbknapp/clap-rs/commit/38fb59abf480eb2b6feca269097412f8b00b5b54), closes [#447](https://github.com/kbknapp/clap-rs/issues/447))
+* **HELP:**
+ * implements optional colored help messages ([abc8f669](https://github.com/kbknapp/clap-rs/commit/abc8f669c3c8193ffc3a3b0ac6c3ac2198794d4f), closes [#483](https://github.com/kbknapp/clap-rs/issues/483))
+ * Add a Templated Help system. ([81e121ed](https://github.com/kbknapp/clap-rs/commit/81e121edd616f7285593f11120c63bcccae0d23e))
+
+#### Bug Fixes
+
+* **HELP:** Adjust Help to semantic changes introduced in 6933b84 ([8d23806b](https://github.com/kbknapp/clap-rs/commit/8d23806bd67530ad412c34a1dcdcb1435555573d))
+
+<a name="v2.2.6"></a>
+### v2.2.6 (2016-04-11)
+
+#### Bug Fixes
+
+* **Arg Groups**: fixes bug where arg name isn't printed properly ([3019a685](https://github.com/kbknapp/clap-rs/commit/3019a685eee747ccbe6be09ad5dddce0b1d1d4db), closes [#476](https://github.com/kbknapp/clap-rs/issues/476))
+
+
+<a name="v2.2.5"></a>
+### v2.2.5 (2016-04-03)
+
+
+#### Bug Fixes
+
+* **Empty Values:** fixes bug where empty values weren't stored ([885d166f](https://github.com/kbknapp/clap-rs/commit/885d166f04eb3fb581898ae5818c6c8032e5a686), closes [#470](https://github.com/kbknapp/clap-rs/issues/470))
+* **Help Message:** fixes bug where arg name is printed twice ([71acf1d5](https://github.com/kbknapp/clap-rs/commit/71acf1d576946658b8bbdb5ae79e6716c43a030f), closes [#472](https://github.com/kbknapp/clap-rs/issues/472))
+
+
+<a name="v2.2.4"></a>
+### v2.2.4 (2016-03-30)
+
+
+#### Bug Fixes
+
+* fixes compiling with debug cargo feature ([d4b55450](https://github.com/kbknapp/clap-rs/commit/d4b554509928031ac0808076178075bb21f8c1da))
+* **Empty Values:** fixes bug where empty values weren't stored ([885d166f](https://github.com/kbknapp/clap-rs/commit/885d166f04eb3fb581898ae5818c6c8032e5a686), closes [#470](https://github.com/kbknapp/clap-rs/issues/470))
+
+
+
+<a name="v2.2.3"></a>
+### v2.2.3 (2016-03-28)
+
+
+#### Bug Fixes
+
+* **Help Subcommand:** fixes issue where help and version flags weren't properly displayed ([205b07bf](https://github.com/kbknapp/clap-rs/commit/205b07bf2e6547851f1290f8cd6b169145e144f1), closes [#466](https://github.com/kbknapp/clap-rs/issues/466))
+
+<a name="v2.2.2"></a>
+### v2.2.2 (2016-03-27)
+
+
+#### Bug Fixes
+
+* **Help Message:** fixes bug with wrapping in the middle of a unicode sequence ([05365ddc](https://github.com/kbknapp/clap-rs/commit/05365ddcc252e4b49e7a75e199d6001a430bd84d), closes [#456](https://github.com/kbknapp/clap-rs/issues/456))
+* **Usage Strings:** fixes small bug where -- would appear needlessly in usage strings ([6933b849](https://github.com/kbknapp/clap-rs/commit/6933b8491c2a7e28cdb61b47dcf10caf33c2f78a), closes [#461](https://github.com/kbknapp/clap-rs/issues/461))
+
+
+<a name="2.2.1"></a>
+### 2.2.1 (2016-03-16)
+
+
+#### Features
+
+* **Help Message:** wraps and aligns the help message of subcommands ([813d75d0](https://github.com/kbknapp/clap-rs/commit/813d75d06fbf077c65762608c0fa5e941cfc393c), closes [#452](https://github.com/kbknapp/clap-rs/issues/452))
+
+#### Bug Fixes
+
+* **Help Message:** fixes a bug where small terminal sizes causing a loop ([1d73b035](https://github.com/kbknapp/clap-rs/commit/1d73b0355236923aeaf6799abc759762ded7e1d0), closes [#453](https://github.com/kbknapp/clap-rs/issues/453))
+
+
+<a name="v2.2.0"></a>
+## v2.2.0 (2016-03-15)
+
+
+#### Features
+
+* **Help Message:** can auto wrap and aligning help text to term width ([e36af026](https://github.com/kbknapp/clap-rs/commit/e36af0266635f23e85e951b9088d561e9a5d1bf6), closes [#428](https://github.com/kbknapp/clap-rs/issues/428))
+* **Help Subcommand:** adds support passing additional subcommands to help subcommand ([2c12757b](https://github.com/kbknapp/clap-rs/commit/2c12757bbdf34ce481f3446c074e24c09c2e60fd), closes [#416](https://github.com/kbknapp/clap-rs/issues/416))
+* **Opts and Flags:** adds support for custom ordering in help messages ([9803b51e](https://github.com/kbknapp/clap-rs/commit/9803b51e799904c0befaac457418ee766ccc1ab9))
+* **Settings:** adds support for automatically deriving custom display order of args ([ad86e433](https://github.com/kbknapp/clap-rs/commit/ad86e43334c4f70e86909689a088fb87e26ff95a), closes [#444](https://github.com/kbknapp/clap-rs/issues/444))
+* **Subcommands:** adds support for custom ordering in help messages ([7d2a2ed4](https://github.com/kbknapp/clap-rs/commit/7d2a2ed413f5517d45988eef0765cdcd663b6372), closes [#442](https://github.com/kbknapp/clap-rs/issues/442))
+
+#### Bug Fixes
+
+* **From Usage:** fixes a bug where adding empty lines werent ignored ([c5c58c86](https://github.com/kbknapp/clap-rs/commit/c5c58c86b9c503d8de19da356a5a5cffb59fbe84))
+
+#### Documentation
+
+* **Groups:** explains required ArgGroups better ([4ff0205b](https://github.com/kbknapp/clap-rs/commit/4ff0205b85a45151b59bbaf090a89df13438380f), closes [#439](https://github.com/kbknapp/clap-rs/issues/439))
+
+<a name="v2.1.2"></a>
+### v2.1.2 (2016-02-24)
+
+#### Bug Fixes
+
+* **Nightly:** fixes failing nightly build ([d752c170](https://github.com/kbknapp/clap-rs/commit/d752c17029598b19037710f204b7943f0830ae75), closes [#434](https://github.com/kbknapp/clap-rs/issues/434))
+
+
+<a name="v2.1.1"></a>
+### v2.1.1 (2016-02-19)
+
+
+#### Documentation
+
+* **AppSettings:** clarifies that AppSettings do not propagate ([3c8db0e9](https://github.com/kbknapp/clap-rs/commit/3c8db0e9be1d24edaad364359513cbb02abb4186), closes [#429](https://github.com/kbknapp/clap-rs/issues/429))
+* **Arg Examples:** adds better examples ([1e79cccc](https://github.com/kbknapp/clap-rs/commit/1e79cccc12937bc0e7cd2aad8e404410798e9fff))
+
+#### Improvements
+
+* **Help:** adds setting for next line help by arg ([066df748](https://github.com/kbknapp/clap-rs/commit/066df7486e684cf50a8479a356a12ba972c34ce1), closes [#427](https://github.com/kbknapp/clap-rs/issues/427))
+
+
+<a name="v2.1.0"></a>
+## v2.1.0 (2016-02-10)
+
+
+#### Features
+
+* **Defult Values:** adds support for default values in args ([73211952](https://github.com/kbknapp/clap-rs/commit/73211952964a79d97b434dd567e6d7d34be7feb5), closes [#418](https://github.com/kbknapp/clap-rs/issues/418))
+
+#### Documentation
+
+* **Default Values:** adds better examples and notes for default values ([9facd74f](https://github.com/kbknapp/clap-rs/commit/9facd74f843ef3807c5d35259558a344e6c25905))
+
+
+<a name="v2.0.6"></a>
+### v2.0.6 (2016-02-09)
+
+
+#### Improvements
+
+* **Positional Arguments:** now displays value name if appropriate ([f0a99916](https://github.com/kbknapp/clap-rs/commit/f0a99916c59ce675515c6dcdfe9a40b130510908), closes [#420](https://github.com/kbknapp/clap-rs/issues/420))
+
+
+<a name="v2.0.5"></a>
+### v2.0.5 (2016-02-05)
+
+
+#### Bug Fixes
+
+* **Multiple Values:** fixes bug where number_of_values wasnt respected ([72c387da](https://github.com/kbknapp/clap-rs/commit/72c387da0bb8a6f526f863770f08bb8ca0d3de03))
+
+
+<a name="v2.0.4"></a>
+### v2.0.4 (2016-02-04)
+
+
+#### Bug Fixes
+
+* adds support for building ArgGroups from standalone YAML ([fcbc7e12](https://github.com/kbknapp/clap-rs/commit/fcbc7e12f5d7b023b8f30cba8cad28a01cf6cd26))
+* Stop lonely hyphens from causing panic ([85b11468](https://github.com/kbknapp/clap-rs/commit/85b11468b0189d5cc15f1cfac5db40d17a0077dc), closes [#410](https://github.com/kbknapp/clap-rs/issues/410))
+* **AppSettings:** fixes bug where subcmds didn't receive parent ver ([a62e4527](https://github.com/kbknapp/clap-rs/commit/a62e452754b3b0e3ac9a15aa8b5330636229ead1))
+
+<a name="v2.0.3"></a>
+### v2.0.3 (2016-02-02)
+
+
+#### Improvements
+
+* **values:** adds support for up to u64::max values per arg ([c7abf7d7](https://github.com/kbknapp/clap-rs/commit/c7abf7d7611e317b0d31d97632e3d2e13570947c))
+* **occurrences:** Allow for more than 256 occurrences of an argument. ([3731ddb3](https://github.com/kbknapp/clap-rs/commit/3731ddb361163f3d6b86844362871e48c80fa530))
+
+#### Features
+
+* **AppSettings:** adds HidePossibleValuesInHelp to skip writing those values ([cdee7a0e](https://github.com/kbknapp/clap-rs/commit/cdee7a0eb2beeec723cb98acfacf03bf629c1da3))
+
+#### Bug Fixes
+
+* **value_t_or_exit:** fixes typo which causes value_t_or_exit to return a Result ([ee96baff](https://github.com/kbknapp/clap-rs/commit/ee96baffd306cb8d20ddc5575cf739bb1a6354e8))
+
+
+<a name="v2.0.2"></a>
+### v2.0.2 (2016-01-31)
+
+
+#### Improvements
+
+* **arg_enum:** enum declared with arg_enum returns [&'static str; #] instead of Vec ([9c4b8a1a](https://github.com/kbknapp/clap-rs/commit/9c4b8a1a6b12949222f17d1074578ad7676b9c0d))
+
+#### Bug Fixes
+
+* clap_app! should be gated by unstable, not nightly feature ([0c8b84af](https://github.com/kbknapp/clap-rs/commit/0c8b84af6161d5baf683688eafc00874846f83fa))
+* **SubCommands:** fixed where subcmds weren't recognized after mult args ([c19c17a8](https://github.com/kbknapp/clap-rs/commit/c19c17a8850602990e24347aeb4427cf43316223), closes [#405](https://github.com/kbknapp/clap-rs/issues/405))
+* **Usage Parser:** fixes a bug where literal single quotes weren't allowed in help strings ([0bcc7120](https://github.com/kbknapp/clap-rs/commit/0bcc71206478074769e311479b34a9f74fe80f5c), closes [#406](https://github.com/kbknapp/clap-rs/issues/406))
+
+
+<a name="v2.0.1"></a>
+### v2.0.1 (2016-01-30)
+
+
+#### Bug Fixes
+
+* fixes cargo features to NOT require nightly with unstable features ([dcbcc60c](https://github.com/kbknapp/clap-rs/commit/dcbcc60c9ba17894be636472ea4b07a82d86a9db), closes [#402](https://github.com/kbknapp/clap-rs/issues/402))
+
+
+<a name="v2.0.0"></a>
+## v2.0.0 (2016-01-28)
+
+
+#### Improvements
+
+* **From Usage:** vastly improves the usage parser ([fa3a2f86](https://github.com/kbknapp/clap-rs/commit/fa3a2f86bd674c5eb07128c95098fab7d1437247), closes [#350](https://github.com/kbknapp/clap-rs/issues/350))
+
+#### Features
+
+* adds support for external subcommands ([177fe5cc](https://github.com/kbknapp/clap-rs/commit/177fe5cce745c2164a8e38c23be4c4460d2d7211), closes [#372](https://github.com/kbknapp/clap-rs/issues/372))
+* adds support values with a leading hyphen ([e4d429b9](https://github.com/kbknapp/clap-rs/commit/e4d429b9d52e95197bd0b572d59efacecf305a59), closes [#385](https://github.com/kbknapp/clap-rs/issues/385))
+* adds support for turning off the value delimiter ([508db850](https://github.com/kbknapp/clap-rs/commit/508db850a87c2e251cf6b6ddead9ad56b29f9e57), closes [#352](https://github.com/kbknapp/clap-rs/issues/352))
+* adds support changing the value delimiter ([dafeae8a](https://github.com/kbknapp/clap-rs/commit/dafeae8a526162640f6a68da434370c64d190889), closes [#353](https://github.com/kbknapp/clap-rs/issues/353))
+* adds support for comma separated values ([e69da6af](https://github.com/kbknapp/clap-rs/commit/e69da6afcd2fe48a3c458ca031db40997f860eda), closes [#348](https://github.com/kbknapp/clap-rs/issues/348))
+* adds support with options with optional values ([4555736c](https://github.com/kbknapp/clap-rs/commit/4555736cad01441dcde4ea84a285227e0844c16e), closes [#367](https://github.com/kbknapp/clap-rs/issues/367))
+* **UTF-8:** adds support for invalid utf8 in values ([c5c59dec](https://github.com/kbknapp/clap-rs/commit/c5c59dec0bc33b86b2e99d30741336f17ec84282), closes [#269](https://github.com/kbknapp/clap-rs/issues/269))
+* **v2:** implementing the base of 2.x ([a3536054](https://github.com/kbknapp/clap-rs/commit/a3536054512ba833533dc56615ce3663d884381c))
+
+#### Bug Fixes
+
+* fixes nightly build with new lints ([17599195](https://github.com/kbknapp/clap-rs/commit/175991956c37dc83ba9c49396e927a1cb65c5b11))
+* fixes Windows build for 2x release ([674c9b48](https://github.com/kbknapp/clap-rs/commit/674c9b48c7c92079cb180cc650a9e39f34781c32), closes [#392](https://github.com/kbknapp/clap-rs/issues/392))
+* fixes yaml build for 2x base ([adceae64](https://github.com/kbknapp/clap-rs/commit/adceae64c8556d00ab715677377b216f9f468ad7))
+
+#### Documentation
+
+* updates examples for 2x release ([1303b360](https://github.com/kbknapp/clap-rs/commit/1303b3607468f362ab1b452d5614c1a064dc69b4), closes [#394](https://github.com/kbknapp/clap-rs/issues/394))
+* updates examples for 2x release ([0a011f31](https://github.com/kbknapp/clap-rs/commit/0a011f3142aec338d388a6c8bfe22fa7036021bb), closes [#394](https://github.com/kbknapp/clap-rs/issues/394))
+* updates documentation for v2 release ([8d51724e](https://github.com/kbknapp/clap-rs/commit/8d51724ef73dfde5bb94fb9466bc5463a1cc1502))
+* updating docs for 2x release ([576d0e0e](https://github.com/kbknapp/clap-rs/commit/576d0e0e2c7b8f386589179bbf7419b93abacf1c))
+* **README.md:**
+ * updates readme for v2 release ([acaba01a](https://github.com/kbknapp/clap-rs/commit/acaba01a353c12144b9cd9a3ce447400691849b0), closes [#393](https://github.com/kbknapp/clap-rs/issues/393))
+ * fix typo and make documentation conspicuous ([07b9f614](https://github.com/kbknapp/clap-rs/commit/07b9f61495d927f69f7abe6c0d85253f0f4e6107))
+
+#### BREAKING CHANGES
+
+* **Fewer liftimes! Yay!**
+ * `App<'a, 'b, 'c, 'd, 'e, 'f>` => `App<'a, 'b>`
+ * `Arg<'a, 'b, 'c, 'd, 'e, 'f>` => `Arg<'a, 'b>`
+ * `ArgMatches<'a, 'b>` => `ArgMatches<'a>`
+* **Simply Renamed**
+ * `App::arg_group` => `App::group`
+ * `App::arg_groups` => `App::groups`
+ * `ArgGroup::add` => `ArgGroup::arg`
+ * `ArgGroup::add_all` => `ArgGroup::args`
+ * `ClapError` => `Error`
+ * struct field `ClapError::error_type` => `Error::kind`
+ * `ClapResult` => `Result`
+ * `ClapErrorType` => `ErrorKind`
+* **Removed Deprecated Functions and Methods**
+ * `App::subcommands_negate_reqs`
+ * `App::subcommand_required`
+ * `App::arg_required_else_help`
+ * `App::global_version(bool)`
+ * `App::versionless_subcommands`
+ * `App::unified_help_messages`
+ * `App::wait_on_error`
+ * `App::subcommand_required_else_help`
+ * `SubCommand::new`
+ * `App::error_on_no_subcommand`
+ * `Arg::new`
+ * `Arg::mutually_excludes`
+ * `Arg::mutually_excludes_all`
+ * `Arg::mutually_overrides_with`
+ * `simple_enum!`
+* **Renamed Error Variants**
+ * `InvalidUnicode` => `InvalidUtf8`
+ * `InvalidArgument` => `UnknownArgument`
+* **Usage Parser**
+ * Value names can now be specified inline, i.e. `-o, --option <FILE> <FILE2> 'some option which takes two files'`
+ * **There is now a priority of order to determine the name** - This is perhaps the biggest breaking change. See the documentation for full details. Prior to this change, the value name took precedence. **Ensure your args are using the proper names (i.e. typically the long or short and NOT the value name) throughout the code**
+* `ArgMatches::values_of` returns an `Values` now which implements `Iterator` (should not break any code)
+* `crate_version!` returns `&'static str` instead of `String`
+* Using the `clap_app!` macro requires compiling with the `unstable` feature because the syntax could change slightly in the future
+
+
+<a name="v1.5.5"></a>
+### v1.5.5 (2016-01-04)
+
+
+#### Bug Fixes
+
+* fixes an issue where invalid short args didn't cause an error ([c9bf7e44](https://github.com/kbknapp/clap-rs/commit/c9bf7e4440bd2f9b524ea955311d433c40a7d1e0))
+* prints the name in version and help instead of binary name ([8f3817f6](https://github.com/kbknapp/clap-rs/commit/8f3817f665c0cab6726bc16c56a53b6a61e44448), closes [#368](https://github.com/kbknapp/clap-rs/issues/368))
+* fixes an intentional panic issue discovered via clippy ([ea83a3d4](https://github.com/kbknapp/clap-rs/commit/ea83a3d421ea8856d4cac763942834d108b71406))
+
+
+<a name="v1.5.4"></a>
+### v1.5.4 (2015-12-18)
+
+
+#### Examples
+
+* **17_yaml:** conditinonally compile 17_yaml example ([575de089](https://github.com/kbknapp/clap-rs/commit/575de089a3e240c398cb10e6cf5a5c6b68662c01))
+
+#### Improvements
+
+* clippy improvements ([99cdebc2](https://github.com/kbknapp/clap-rs/commit/99cdebc23da3a45a165f14b27bebeb2ed828a2ce))
+
+#### Bug Fixes
+
+
+* **errors:** return correct error type in WrongNumValues error builder ([5ba8ba9d](https://github.com/kbknapp/clap-rs/commit/5ba8ba9dcccdfa74dd1c44260e64b359bbb36be6))
+* ArgRequiredElseHelp setting now takes precedence over missing required args ([faad83fb](https://github.com/kbknapp/clap-rs/commit/faad83fbef6752f3093b6e98fca09a9449b830f4), closes [#362](https://github.com/kbknapp/clap-rs/issues/362))
+
+
+<a name="v1.5.3"></a>
+### v1.5.3 (2015-11-20)
+
+
+#### Bug Fixes
+
+* **Errors:** fixes some instances when errors are missing a final newline ([c4d2b171](https://github.com/kbknapp/clap-rs/commit/c4d2b1711994479ad64ee52b6b49d2ceccbf2118))
+
+
+
+
+<a name="v1.5.2"></a>
+### v1.5.2 (2015-11-14)
+
+
+#### Bug Fixes
+
+* **Errors:** fixes a compiling bug when built on Windows or without the color feature ([a35f7634](https://github.com/kbknapp/clap-rs/commit/a35f76346fe6ecc88dda6a1eb13627186e7ce185))
+
+
+
+<a name="v1.5.1"></a>
+### v1.5.1 (2015-11-13)
+
+
+#### Bug Fixes
+
+* **Required Args:** fixes a bug where required args are not correctly accounted for ([f03b88a9](https://github.com/kbknapp/clap-rs/commit/f03b88a9766b331a63879bcd747687f2e5a2661b), closes [#343](https://github.com/kbknapp/clap-rs/issues/343))
+
+
+
+<a name="v1.5.0"></a>
+## v1.5.0 (2015-11-13)
+
+
+#### Bug Fixes
+
+* fixes a bug with required positional args in usage strings ([c6858f78](https://github.com/kbknapp/clap-rs/commit/c6858f78755f8e860204323c828c8355a066dc83))
+
+#### Documentation
+
+* **FAQ:** updates readme with slight changes to FAQ ([a4ef0fab](https://github.com/kbknapp/clap-rs/commit/a4ef0fab73c8dc68f1b138965d1340459c113398))
+
+#### Improvements
+
+* massive errors overhaul ([cdc29175](https://github.com/kbknapp/clap-rs/commit/cdc29175bc9c53e5b4aec86cbc04c1743154dae6))
+* **ArgMatcher:** huge refactor and deduplication of code ([8988853f](https://github.com/kbknapp/clap-rs/commit/8988853fb8825e8f841fde349834cc12cdbad081))
+* **Errors:** errors have been vastly improved ([e59bc0c1](https://github.com/kbknapp/clap-rs/commit/e59bc0c16046db156a88ba71a037db05028e995c))
+* **Traits:** refactoring some configuration into traits ([5800cdec](https://github.com/kbknapp/clap-rs/commit/5800cdec6dce3def4242b9f7bd136308afb19685))
+
+#### Performance
+
+* **App:**
+ * more BTreeMap->Vec, Opts and SubCmds ([bc4495b3](https://github.com/kbknapp/clap-rs/commit/bc4495b32ec752b6c4b29719e831c043ef2a26ce))
+ * changes flags BTreeMap->Vec ([d357640f](https://github.com/kbknapp/clap-rs/commit/d357640fab55e5964fe83efc3c771e53aa3222fd))
+ * removed unneeded BTreeMap ([78971fd6](https://github.com/kbknapp/clap-rs/commit/78971fd68d7dc5c8e6811b4520cdc54e4188f733))
+ * changes BTreeMap to VecMap in some instances ([64b921d0](https://github.com/kbknapp/clap-rs/commit/64b921d087fdd03775c95ba0bcf65d3f5d36f812))
+ * removed excess clones ([ec0089d4](https://github.com/kbknapp/clap-rs/commit/ec0089d42ed715d293fb668d3a90b0db0aa3ec39))
+
+
+
+<a name="v1.4.7"></a>
+### v1.4.7 (2015-11-03)
+
+
+#### Documentation
+
+* Clarify behavior of Arg::multiple with options. ([434f497a](https://github.com/kbknapp/clap-rs/commit/434f497ab6d831f8145cf09278c97ca6ee6c6fe7))
+* Fix typos and improve grammar. ([c1f66b5d](https://github.com/kbknapp/clap-rs/commit/c1f66b5de7b5269fbf8760a005ef8c645edd3229))
+
+#### Bug Fixes
+
+* **Error Status:** fixes bug where --help and --version return non-zero exit code ([89b51fdf](https://github.com/kbknapp/clap-rs/commit/89b51fdf8b1ab67607567344e2317ff1a757cb12))
+
+
+
+<a name="v1.4.6"></a>
+### v1.4.6 (2015-10-29)
+
+
+#### Features
+
+* allows parsing without a binary name for daemons and interactive CLIs ([aff89d57](https://github.com/kbknapp/clap-rs/commit/aff89d579b5b85c3dc81b64f16d5865299ec39a2), closes [#318](https://github.com/kbknapp/clap-rs/issues/318))
+
+#### Bug Fixes
+
+* **Errors:** tones down quoting in some error messages ([34ce59ed](https://github.com/kbknapp/clap-rs/commit/34ce59ede53bfa2eef722c74881cdba7419fd9c7), closes [#309](https://github.com/kbknapp/clap-rs/issues/309))
+* **Help and Version:** only builds help and version once ([e3be87cf](https://github.com/kbknapp/clap-rs/commit/e3be87cfc095fc41c9811adcdc6d2b079f237d5e))
+* **Option Args:** fixes bug with args and multiple values ([c9a9548a](https://github.com/kbknapp/clap-rs/commit/c9a9548a8f96cef8a3dd9a980948325fbbc1b91b), closes [#323](https://github.com/kbknapp/clap-rs/issues/323))
+* **POSIX Overrides:** fixes bug where required args are overridden ([40ed2b50](https://github.com/kbknapp/clap-rs/commit/40ed2b50c3a9fe88bfdbaa43cef9fd6493ecaa8e))
+* **Safe Matches:** using 'safe' forms of the get_matches family no longer exit the process ([c47025dc](https://github.com/kbknapp/clap-rs/commit/c47025dca2b3305dea0a0acfdd741b09af0c0d05), closes [#256](https://github.com/kbknapp/clap-rs/issues/256))
+* **Versionless SubCommands:** fixes a bug where the -V flag was needlessly built ([27df8b9d](https://github.com/kbknapp/clap-rs/commit/27df8b9d98d13709dad3929a009f40ebff089a1a), closes [#329](https://github.com/kbknapp/clap-rs/issues/329))
+
+#### Documentation
+
+* adds comparison in readme ([1a8bf31e](https://github.com/kbknapp/clap-rs/commit/1a8bf31e7a6b87ce48a66af2cde1645b2dd5bc95), closes [#325](https://github.com/kbknapp/clap-rs/issues/325))
+
+
+
+<a name="v1.4.5"></a>
+### v1.4.5 (2015-10-06)
+
+
+#### Bug Fixes
+
+* fixes crash on invalid arg error ([c78ce128](https://github.com/kbknapp/clap-rs/commit/c78ce128ebbe7b8f730815f8176c29d76f4ade8c))
+
+
+
+<a name="v1.4.4"></a>
+### v1.4.4 (2015-10-06)
+
+
+#### Documentation
+
+* clean up some formatting ([b7df92d7](https://github.com/kbknapp/clap-rs/commit/b7df92d7ea25835701dd22ddff984b9749f48a00))
+* move the crate-level docs to top of the lib.rs file ([d7233bf1](https://github.com/kbknapp/clap-rs/commit/d7233bf122dbf80ba8fc79e5641be2df8af10e7a))
+* changes doc comments to rustdoc comments ([34b601be](https://github.com/kbknapp/clap-rs/commit/34b601be5fdde76c1a0859385b359b96d66b8732))
+* fixes panic in 14_groups example ([945b00a0](https://github.com/kbknapp/clap-rs/commit/945b00a0c27714b63bdca48d003fe205fcfdc578), closes [#295](https://github.com/kbknapp/clap-rs/issues/295))
+* avoid suggesting star dependencies. ([d33228f4](https://github.com/kbknapp/clap-rs/commit/d33228f40b5fefb84cf3dd51546bfb340dcd9f5a))
+* **Rustdoc:** adds portions of the readme to main rustdoc page ([6f9ee181](https://github.com/kbknapp/clap-rs/commit/6f9ee181e69d90bd4206290e59d6f3f1e8f0cbb2), closes [#293](https://github.com/kbknapp/clap-rs/issues/293))
+
+#### Bug Fixes
+
+* grammar error in some conflicting option errors ([e73b07e1](https://github.com/kbknapp/clap-rs/commit/e73b07e19474323ad2260da66abbf6a6d4ecbd4f))
+* **Unified Help:** sorts both flags and options as a unified category ([2a223dad](https://github.com/kbknapp/clap-rs/commit/2a223dad82901fa2e74baad3bfc4c7b94509300f))
+* **Usage:** fixes a bug where required args aren't filtered properly ([72b453dc](https://github.com/kbknapp/clap-rs/commit/72b453dc170af3050bb123d35364f6da77fc06d7), closes [#277](https://github.com/kbknapp/clap-rs/issues/277))
+* **Usage Strings:** fixes a bug ordering of elements in usage strings ([aaf0d6fe](https://github.com/kbknapp/clap-rs/commit/aaf0d6fe7aa2403e76096c16204d254a9ee61ee2), closes [#298](https://github.com/kbknapp/clap-rs/issues/298))
+
+#### Features
+
+* supports -aValue style options ([0e3733e4](https://github.com/kbknapp/clap-rs/commit/0e3733e4fec2015c2d566a51432dcd92cb69cad3))
+* **Trailing VarArg:** adds opt-in setting for final arg being vararg ([27018b18](https://github.com/kbknapp/clap-rs/commit/27018b1821a4bcd5235cfe92abe71b3c99efc24d), closes [#278](https://github.com/kbknapp/clap-rs/issues/278))
+
+
+
+<a name="v1.4.3"></a>
+### v1.4.3 (2015-09-30)
+
+
+#### Features
+
+* allows accessing arg values by group name ([c92a4b9e](https://github.com/kbknapp/clap-rs/commit/c92a4b9eff2d679957f61c0c41ff404b40d38a91))
+
+#### Documentation
+
+* use links to examples instead of plain text ([bb4fe237](https://github.com/kbknapp/clap-rs/commit/bb4fe237858535627271465147add537e4556b43))
+
+#### Bug Fixes
+
+* **Help Message:** required args no longer double list in usage ([1412e639](https://github.com/kbknapp/clap-rs/commit/1412e639e0a79df84936d1101a837f90077d1c83), closes [#277](https://github.com/kbknapp/clap-rs/issues/277))
+* **Possible Values:** possible value validation is restored ([f121ae74](https://github.com/kbknapp/clap-rs/commit/f121ae749f8f4bfe754ef2e8a6dfc286504b5b75), closes [#287](https://github.com/kbknapp/clap-rs/issues/287))
+
+
+
+<a name="v1.4.2"></a>
+### v1.4.2 (2015-09-23)
+
+
+#### Bug Fixes
+
+* **Conflicts:** fixes bug with conflicts not removing required args ([e17fcec5](https://github.com/kbknapp/clap-rs/commit/e17fcec53b3216ad047a13dddc6f740473fad1a1), closes [#271](https://github.com/kbknapp/clap-rs/issues/271))
+
+
+
+<a name="v1.4.1"></a>
+### v1.4.1 (2015-09-22)
+
+
+#### Examples
+
+* add clap_app quick example ([4ba6249c](https://github.com/kbknapp/clap-rs/commit/4ba6249c3cf4d2e083370d1fe4dcc7025282c28a))
+
+#### Features
+
+* **Unicode:** allows non-panicing on invalid unicode characters ([c5bf7ddc](https://github.com/kbknapp/clap-rs/commit/c5bf7ddc8cfb876ec928a5aaf5591232bbb32e5d))
+
+#### Documentation
+
+* properly names Examples section for rustdoc ([87ba5445](https://github.com/kbknapp/clap-rs/commit/87ba54451d7ec7b1c9b9ef134f90bbe39e6fac69))
+* fixes various typos and spelling ([f85640f9](https://github.com/kbknapp/clap-rs/commit/f85640f9f6d8fd3821a40e9b8b7a34fabb789d02))
+* **Arg:** unhides fields of the Arg struct ([931aea88](https://github.com/kbknapp/clap-rs/commit/931aea88427edf43a3da90d5a500c1ff2b2c3614))
+
+#### Bug Fixes
+
+* flush the buffer in App::print_version() ([cbc42a37](https://github.com/kbknapp/clap-rs/commit/cbc42a37d212d84d22b1777d08e584ff191934e7))
+* Macro benchmarks ([13712da1](https://github.com/kbknapp/clap-rs/commit/13712da1d36dc7614eec3a10ad488257ba615751))
+
+
+
+<a name="v1.4.0"></a>
+## v1.4.0 (2015-09-09)
+
+
+#### Features
+
+* allows printing help message by library consumers ([56b95f32](https://github.com/kbknapp/clap-rs/commit/56b95f320875c62dda82cb91b29059671e120ed1))
+* allows defining hidden args and subcmds ([2cab4d03](https://github.com/kbknapp/clap-rs/commit/2cab4d0334ea3c2439a1d4bfca5bf9905c7ea9ac), closes [#231](https://github.com/kbknapp/clap-rs/issues/231))
+* Builder macro to assist with App/Arg/Group/SubCommand building ([443841b0](https://github.com/kbknapp/clap-rs/commit/443841b012a8d795cd5c2bd69ae6e23ef9b16477))
+* **Errors:** allows consumers to write to stderr and exit on error ([1e6403b6](https://github.com/kbknapp/clap-rs/commit/1e6403b6a863574fa3cb6946b1fb58f034e8664c))
+
+
+
+<a name="v1.3.2"></a>
+### v1.3.2 (2015-09-08)
+
+
+#### Documentation
+
+* fixed ErrorKind docs ([dd057843](https://github.com/kbknapp/clap-rs/commit/dd05784327fa070eb6ce5ce89a8507e011d8db94))
+* **ErrorKind:** changed examples content ([b9ca2616](https://github.com/kbknapp/clap-rs/commit/b9ca261634b89613bbf3d98fd74d55cefbb31a8c))
+
+#### Bug Fixes
+
+* fixes a bug where the help subcommand wasn't overridable ([94003db4](https://github.com/kbknapp/clap-rs/commit/94003db4b5eebe552ca337521c1c001295822745))
+
+#### Features
+
+* adds abiltiy not consume self when parsing matches and/or exit on help ([94003db4](https://github.com/kbknapp/clap-rs/commit/94003db4b5eebe552ca337521c1c001295822745))
+* **App:** Added ability for users to handle errors themselves ([934e6fbb](https://github.com/kbknapp/clap-rs/commit/934e6fbb643b2385efc23444fe6fce31494dc288))
+
+
+
+<a name="v1.3.1"></a>
+### v1.3.1 (2015-09-04)
+
+
+#### Examples
+
+* **17_yaml:** fixed example ([9b848622](https://github.com/kbknapp/clap-rs/commit/9b848622296c8c5c7b9a39b93ddd41f51df790b5))
+
+#### Performance
+
+* changes ArgGroup HashSets to Vec ([3cb4a48e](https://github.com/kbknapp/clap-rs/commit/3cb4a48ebd15c20692f4f3a2a924284dc7fd5e10))
+* changes BTreeSet for Vec in some instances ([baab2e3f](https://github.com/kbknapp/clap-rs/commit/baab2e3f4060e811abee14b1654cbcd5cf3b5fea))
+
+
+
+<a name="v1.3.0"></a>
+## v1.3.0 (2015-09-01)
+
+
+#### Features
+
+* **YAML:** allows building a CLI from YAML files ([86cf4c45](https://github.com/kbknapp/clap-rs/commit/86cf4c45626a36b8115446952f9069f73c1debc3))
+* **ArgGroups:** adds support for building ArgGroups from yaml ([ecf88665](https://github.com/kbknapp/clap-rs/commit/ecf88665cbff367018b29161a1b75d44a212707d))
+* **Subcommands:** adds support for subcommands from yaml ([e415cf78](https://github.com/kbknapp/clap-rs/commit/e415cf78ba916052d118a8648deba2b9c16b1530))
+
+#### Documentation
+
+* **YAML:** adds examples for using YAML to build a CLI ([ab41d7f3](https://github.com/kbknapp/clap-rs/commit/ab41d7f38219544750e6e1426076dc498073191b))
+* **Args from YAML:** fixes doc examples ([19b348a1](https://github.com/kbknapp/clap-rs/commit/19b348a10050404cd93888dbbbe4f396681b67d0))
+* **Examples:** adds better usage examples instead of having unused variables ([8cbacd88](https://github.com/kbknapp/clap-rs/commit/8cbacd8883004fe71a8ea036ec4391c7dd8efe94))
+
+#### Examples
+
+* Add AppSettings example ([12705079](https://github.com/kbknapp/clap-rs/commit/12705079ca96a709b4dd94f7ddd20a833b26838c))
+
+#### Bug Fixes
+
+* **Unified Help Messages:** fixes a crash from this setting and no opts ([169ffec1](https://github.com/kbknapp/clap-rs/commit/169ffec1003d58d105d7ef2585b3425e57980000), closes [#210](https://github.com/kbknapp/clap-rs/issues/210))
+
+
+
+<a name="v1.2.5"></a>
+### v1.2.5 (2015-08-27)
+
+
+#### Examples
+
+* add custom validator example ([b9997d1f](https://github.com/kbknapp/clap-rs/commit/b9997d1fca74d4d8f93971f2a01bdf9798f913d5))
+* fix indentation ([d4f1b740](https://github.com/kbknapp/clap-rs/commit/d4f1b740ede410fd2528b9ecd89592c2fd8b1e20))
+
+#### Features
+
+* **Args:** allows opts and args to define a name for help and usage msgs ([ad962ec4](https://github.com/kbknapp/clap-rs/commit/ad962ec478da999c7dba0afdb84c266f4d09b1bd))
+
+
+
+<a name="v1.2.4"></a>
+### v1.2.4 (2015-08-26)
+
+
+#### Bug Fixes
+
+* **Possible Values:** fixes a bug where suggestions arent made when using --long=value format ([3d5e9a6c](https://github.com/kbknapp/clap-rs/commit/3d5e9a6cedb26668839b481c9978e2fbbab8be6f), closes [#192](https://github.com/kbknapp/clap-rs/issues/192))
+
+
+
+<a name="v1.2.3"></a>
+### v1.2.3 (2015-08-24)
+
+
+#### Bug Fixes
+
+* **App, Args:** fixed subcommand reqs negation ([b41afa8c](https://github.com/kbknapp/clap-rs/commit/b41afa8c3ded3d1be12f7a2f8ea06cc44afc9458), closes [#188](https://github.com/kbknapp/clap-rs/issues/188))
+
+
+
+<a name="v1.2.2"></a>
+### v1.2.2 (2015-08-23)
+
+
+#### Bug Fixes
+
+* fixed confusing error message, also added test for it ([fc7a31a7](https://github.com/kbknapp/clap-rs/commit/fc7a31a745efbf1768ee2c62cd3bb72bfe30c708))
+* **App:** fixed requirmets overriding ([9c135eb7](https://github.com/kbknapp/clap-rs/commit/9c135eb790fa16183e5bdb2009ddc3cf9e25f99f))
+
+
+
+<a name="v1.2.1"></a>
+### v1.2.1 (2015-08-20)
+
+
+#### Documentation
+
+* **README.md:** updates for new features ([16cf9245](https://github.com/kbknapp/clap-rs/commit/16cf9245fb5fc4cf6face898e358368bf9961cbb))
+
+#### Features
+
+* implements posix compatible conflicts for long args ([8c2d48ac](https://github.com/kbknapp/clap-rs/commit/8c2d48acf5473feebd721a9049a9c9b7051e70f9))
+* added overrides to support conflicts in POSIX compatible manner ([0b916a00](https://github.com/kbknapp/clap-rs/commit/0b916a00de26f6941538f6bc5f3365fa302083c1))
+* **Args:** allows defining POSIX compatible argument conflicts ([d715646e](https://github.com/kbknapp/clap-rs/commit/d715646e69759ccd95e01f49b04f489827ecf502))
+
+#### Bug Fixes
+
+* fixed links in cargo and license buttons ([6d9837ad](https://github.com/kbknapp/clap-rs/commit/6d9837ad9a9e006117cd7372fdc60f9a3889c7e2))
+
+#### Performance
+
+* **Args and Apps:** changes HashSet->Vec in some instances for increased performance ([d0c3b379](https://github.com/kbknapp/clap-rs/commit/d0c3b379700757e0a9b0c40af709f8af1f5b4949))
+
+
+
+<a name="v1.2.0"></a>
+### v1.2.0 (2015-08-15)
+
+
+#### Bug Fixes
+
+* fixed misspell and enum name ([7df170d7](https://github.com/kbknapp/clap-rs/commit/7df170d7f4ecff06608317655d1e0c4298f62076))
+* fixed use for clap crate ([dc3ada73](https://github.com/kbknapp/clap-rs/commit/dc3ada738667d4b689678f79d14251ee82004ece))
+
+#### Documentation
+
+* updates docs for new features ([03496547](https://github.com/kbknapp/clap-rs/commit/034965471782d872ca495045b58d34b31807c5b1))
+* fixed docs for previous changes ([ade36778](https://github.com/kbknapp/clap-rs/commit/ade367780c366425de462506d256e0f554ed3b9c))
+
+#### Improvements
+
+* **AppSettings:** adds ability to add multiple settings at once ([4a00e251](https://github.com/kbknapp/clap-rs/commit/4a00e2510d0ca8d095d5257d51691ba3b61c1374))
+
+#### Features
+
+* Replace application level settings with enum variants ([618dc4e2](https://github.com/kbknapp/clap-rs/commit/618dc4e2c205bf26bc43146164e65eb1f6b920ed))
+* **Args:** allows for custom argument value validations to be defined ([84ae2ddb](https://github.com/kbknapp/clap-rs/commit/84ae2ddbceda34b5cbda98a6959edaa52fde2e1a), closes [#170](https://github.com/kbknapp/clap-rs/issues/170))
+
+
+
+<a name="v1.1.6"></a>
+### v1.1.6 (2015-08-01)
+
+
+#### Bug Fixes
+
+* fixes two bugs in App when printing newlines in help and subcommands required error ([d63c0136](https://github.com/kbknapp/clap-rs/commit/d63c0136310db9dd2b1c7b4745938311601d8938))
+
+
+
+<a name="v1.1.5"></a>
+### v1.1.5 (2015-07-29)
+
+#### Performance
+
+* removes some unneeded allocations ([93e915df](https://github.com/kbknapp/clap-rs/commit/93e915dfe300f7b7d6209ca93323c6a46f89a8c1))
+
+<a name="v1.1.4"></a>
+### v1.1.4 (2015-07-20)
+
+
+#### Improvements
+
+* **Usage Strings** displays a [--] when it may be helpful ([86c3be85](https://github.com/kbknapp/clap-rs/commit/86c3be85fb6f77f83b5a6d2df40ae60937486984))
+
+#### Bug Fixes
+
+* **Macros** fixes a typo in a macro generated error message ([c9195c5f](https://github.com/kbknapp/clap-rs/commit/c9195c5f92abb8cd6a37b4f4fbb2f1fee2a8e368))
+* **Type Errors** fixes formatting of error output when failed type parsing ([fe5d95c6](https://github.com/kbknapp/clap-rs/commit/fe5d95c64f3296e6eddcbec0cb8b86659800145f))
+
+
+
+<a name="v1.1.3"></a>
+### v1.1.3 (2015-07-18)
+
+
+#### Documentation
+
+* updates README.md to include lack of color support on Windows ([52f81e17](https://github.com/kbknapp/clap-rs/commit/52f81e17377b18d2bd0f34693b642b7f358998ee))
+
+#### Bug Fixes
+
+* fixes formatting bug which prevented compiling on windows ([9cb5dceb](https://github.com/kbknapp/clap-rs/commit/9cb5dceb3e5fe5e0e7b24619ff77e5040672b723), closes [#163](https://github.com/kbknapp/clap-rs/issues/163))
+
+
+
+<a name="v1.1.2"></a>
+### v1.1.2 (2015-07-17)
+
+
+#### Bug Fixes
+
+* fixes a bug when parsing multiple {n} newlines inside help strings ([6d214b54](https://github.com/kbknapp/clap-rs/commit/6d214b549a9b7e189a94e5fa2b7c92cc333ca637))
+
+
+
+<a name="v1.1.1"></a>
+## v1.1.1 (2015-07-17)
+
+
+#### Bug Fixes
+
+* fixes a logic bug and allows setting Arg::number_of_values() < 2 ([42b6d1fc](https://github.com/kbknapp/clap-rs/commit/42b6d1fc3c519c92dfb3af15276e7d3b635e6cfe), closes [#161](https://github.com/kbknapp/clap-rs/issues/161))
+
+
+
+<a name="v1.1.0"></a>
+## v1.1.0 (2015-07-16)
+
+
+#### Features
+
+* allows creating unified help messages, a la docopt or getopts ([52bcd892](https://github.com/kbknapp/clap-rs/commit/52bcd892ea51564ce463bc5865acd64f8fe91cb1), closes [#158](https://github.com/kbknapp/clap-rs/issues/158))
+* allows stating all subcommands should *not* have --version flags ([336c476f](https://github.com/kbknapp/clap-rs/commit/336c476f631d512b54ac56fdca6f29ebdc2c00c5), closes [#156](https://github.com/kbknapp/clap-rs/issues/156))
+* allows setting version number to auto-propagate through subcommands ([bc66d3c6](https://github.com/kbknapp/clap-rs/commit/bc66d3c6deedeca62463fff95369ab1cfcdd366b), closes [#157](https://github.com/kbknapp/clap-rs/issues/157))
+
+#### Improvements
+
+* **Help Strings** properly aligns and handles newlines in long help strings ([f9800a29](https://github.com/kbknapp/clap-rs/commit/f9800a29696dd2cc0b0284bf693b3011831e556f), closes [#145](https://github.com/kbknapp/clap-rs/issues/145))
+
+
+#### Performance
+
+* **Help Messages** big performance improvements when printing help messages ([52bcd892](https://github.com/kbknapp/clap-rs/commit/52bcd892ea51564ce463bc5865acd64f8fe91cb1))
+
+#### Documentation
+
+* updates readme with new features ([8232f7bb](https://github.com/kbknapp/clap-rs/commit/8232f7bb52e88862bc13c3d4f99ee4f56cfe4bc0))
+* fix incorrect code example for `App::subcommand_required` ([8889689d](https://github.com/kbknapp/clap-rs/commit/8889689dc6336ccc45b2c9f2cf8e2e483a639e93))
+
+
+<a name="v1.0.3"></a>
+### v1.0.3 (2015-07-11)
+
+
+#### Improvements
+
+* **Errors** writes errors to stderr ([cc76ab8c](https://github.com/kbknapp/clap-rs/commit/cc76ab8c2b77c67b42f4717ded530df7806142cf), closes [#154](https://github.com/kbknapp/clap-rs/issues/154))
+
+#### Documentation
+
+* **README.md** updates example help message to new format ([0aca29bd](https://github.com/kbknapp/clap-rs/commit/0aca29bd5d6d1a4e9971bdc88d946ffa58606efa))
+
+
+
+<a name="v1.0.2"></a>
+### v1.0.2 (2015-07-09)
+
+
+#### Improvements
+
+* **Usage** re-orders optional arguments and required to natural standard ([dc7e1fce](https://github.com/kbknapp/clap-rs/commit/dc7e1fcea5c85d317018fb201d2a9262249131b4), closes [#147](https://github.com/kbknapp/clap-rs/issues/147))
+
+
+
+<a name="v1.0.1"></a>
+### v1.0.1 (2015-07-08)
+
+
+#### Bug Fixes
+
+* allows empty values when using --long='' syntax ([083f82d3](https://github.com/kbknapp/clap-rs/commit/083f82d333b69720a6ef30074875310921d964d1), closes [#151](https://github.com/kbknapp/clap-rs/issues/151))
+
+
+
+<a name="v1.0.0"></a>
+## v1.0.0 (2015-07-08)
+
+
+#### Documentation
+
+* **README.md** adds new features to what's new list ([938f7f01](https://github.com/kbknapp/clap-rs/commit/938f7f01340f521969376cf4e2e3d9436bca21f7))
+* **README.md** use with_name for subcommands ([28b7e316](https://github.com/kbknapp/clap-rs/commit/28b7e3161fb772e5309042648fe8c3a420645bac))
+
+#### Features
+
+* args can now be parsed from arbitrary locations, not just std::env::args() ([75312528](https://github.com/kbknapp/clap-rs/commit/753125282b1b9bfff875f1557ce27610edcc59e1))
+
+
+
+<a name="v1.0.0"></a>
+## v1.0.0-beta (2015-06-30)
+
+
+#### Features
+
+* allows waiting for user input on error ([d0da3bdd](https://github.com/kbknapp/clap-rs/commit/d0da3bdd9d1871541907ea9c645322a74d260e07), closes [#140](https://github.com/kbknapp/clap-rs/issues/140))
+* **Help** allows one to fully override the auto-generated help message ([26d5ae3e](https://github.com/kbknapp/clap-rs/commit/26d5ae3e330d1e150811d5b60b2b01a8f8df854e), closes [#141](https://github.com/kbknapp/clap-rs/issues/141))
+
+#### Documentation
+
+* adds "whats new" section to readme ([ff149a29](https://github.com/kbknapp/clap-rs/commit/ff149a29dd9e179865e6d577cd7dc87c54f8f95c))
+
+#### Improvements
+
+* removes deprecated functions in prep for 1.0 ([274484df](https://github.com/kbknapp/clap-rs/commit/274484dfd08fff4859cefd7e9bef3b73d3a9cb5f))
+
+
+
+<a name="v0.11.0"></a>
+## v0.11.0 (2015-06-17) - BREAKING CHANGE
+
+
+#### Documentation
+
+* updates docs to new version flag defaults ([ebf442eb](https://github.com/kbknapp/clap-rs/commit/ebf442ebebbcd2ec6bfe2c06566c9d362bccb112))
+
+#### Features
+
+* **Help and Version** default short for version is now `-V` but can be overridden (only breaks manual documentation) (**BREAKING CHANGE** [eb1d9320](https://github.com/kbknapp/clap-rs/commit/eb1d9320c509c1e4e57d7c7959da82bcfe06ada0))
+
+
+
+<a name="v0.10.5"></a>
+### v0.10.5 (2015-06-06)
+
+
+#### Bug Fixes
+
+* **Global Args** global arguments propogate fully now ([1f377960](https://github.com/kbknapp/clap-rs/commit/1f377960a48c82f54ca5f39eb56bcb393140b046), closes [#137](https://github.com/kbknapp/clap-rs/issues/137))
+
+
+
+<a name="v0.10.4"></a>
+### v0.10.4 (2015-06-06)
+
+
+#### Bug Fixes
+
+* **Global Args** global arguments propogate fully now ([8f2c0160](https://github.com/kbknapp/clap-rs/commit/8f2c0160c8d844daef375a33dbaec7d89de00a00), closes [#137](https://github.com/kbknapp/clap-rs/issues/137))
+
+
+
+<a name="v0.10.3"></a>
+### v0.10.3 (2015-05-31)
+
+
+#### Bug Fixes
+
+* **Global Args** fixes a bug where globals only transfer to one subcommand ([a37842ee](https://github.com/kbknapp/clap-rs/commit/a37842eec1ee3162b86fdbda23420b221cdb1e3b), closes [#135](https://github.com/kbknapp/clap-rs/issues/135))
+
+
+
+<a name="v0.10.2"></a>
+### v0.10.2 (2015-05-30)
+
+
+#### Improvements
+
+* **Binary Names** allows users to override the system determined bin name ([2191fe94](https://github.com/kbknapp/clap-rs/commit/2191fe94bda35771383b52872fb7f5421b178be1), closes [#134](https://github.com/kbknapp/clap-rs/issues/134))
+
+#### Documentation
+
+* adds contributing guidelines ([6f76bd0a](https://github.com/kbknapp/clap-rs/commit/6f76bd0a07e8b7419b391243ab2d6687cd8a9c5f))
+
+
+
+<a name="v0.10.1"></a>
+### v0.10.1 (2015-05-26)
+
+
+#### Features
+
+* can now specify that an app or subcommand should display help on no args or subcommands ([29ca7b2f](https://github.com/kbknapp/clap-rs/commit/29ca7b2f74376ca0cdb9d8ee3bfa99f7640cc404), closes [#133](https://github.com/kbknapp/clap-rs/issues/133))
+
+
+
+<a name="v0.10.0"></a>
+## v0.10.0 (2015-05-23)
+
+
+#### Features
+
+* **Global Args** allows args that propagate down to child commands ([2bcc6137](https://github.com/kbknapp/clap-rs/commit/2bcc6137a83cb07757771a0afea953e68e692f0b), closes [#131](https://github.com/kbknapp/clap-rs/issues/131))
+
+#### Improvements
+
+* **Colors** implements more structured colored output ([d6c3ed54](https://github.com/kbknapp/clap-rs/commit/d6c3ed54d21cf7b40d9f130d4280ff5448522fc5), closes [#129](https://github.com/kbknapp/clap-rs/issues/129))
+
+#### Deprecations
+
+* **SubCommand/App** several methods and functions for stable release ([28b73855](https://github.com/kbknapp/clap-rs/commit/28b73855523ad170544afdb20665db98702fbe70))
+
+#### Documentation
+
+* updates for deprecations and new features ([743eefe8](https://github.com/kbknapp/clap-rs/commit/743eefe8dd40c1260065ce086d572e9e9358bc4c))
+
+
+
+<a name="v0.9.2"></a>
+## v0.9.2 (2015-05-20)
+
+
+#### Bug Fixes
+
+* **help** allows parent requirements to be ignored with help and version ([52218cc1](https://github.com/kbknapp/clap-rs/commit/52218cc1fdb06a42456c964d98cc2c7ac3432412), closes [#124](https://github.com/kbknapp/clap-rs/issues/124))
+
+
+
+<a name="v0.9.1"></a>
+## v0.9.1 (2015-05-18)
+
+
+#### Bug Fixes
+
+* **help** fixes a bug where requirements are included as program name in help and version ([08ba3f25](https://github.com/kbknapp/clap-rs/commit/08ba3f25cf38b149229ba8b9cb37a5804fe6b789))
+
+
+
+<a name="v0.9.0"></a>
+## v0.9.0 (2015-05-17)
+
+
+#### Improvements
+
+* **usage** usage strings now include parent command requirements ([dd8f21c7](https://github.com/kbknapp/clap-rs/commit/dd8f21c7c15cde348fdcf44fa7c205f0e98d2e4a), closes [#125](https://github.com/kbknapp/clap-rs/issues/125))
+* **args** allows consumer of clap to decide if empty values are allowed or not ([ab4ec609](https://github.com/kbknapp/clap-rs/commit/ab4ec609ccf692b9b72cccef5c9f74f5577e360d), closes [#122](https://github.com/kbknapp/clap-rs/issues/122))
+
+#### Features
+
+* **subcommands**
+ * allows optionally specifying that no subcommand is an error ([7554f238](https://github.com/kbknapp/clap-rs/commit/7554f238fd3afdd60b7e4dcf00ff4a9eccf842c1), closes [#126](https://github.com/kbknapp/clap-rs/issues/126))
+ * subcommands can optionally negate parent requirements ([4a4229f5](https://github.com/kbknapp/clap-rs/commit/4a4229f500e21c350e1ef78dd09ef27559653288), closes [#123](https://github.com/kbknapp/clap-rs/issues/123))
+
+
+
+<a name="v0.8.6"></a>
+## v0.8.6 (2015-05-17)
+
+
+#### Bug Fixes
+
+* **args** `-` can now be parsed as a value for an argument ([bc12e78e](https://github.com/kbknapp/clap-rs/commit/bc12e78eadd7eaf9d008a8469fdd2dfd7990cb5d), closes [#121](https://github.com/kbknapp/clap-rs/issues/121))
+
+
+
+<a name="v0.8.5"></a>
+## v0.8.5 (2015-05-15)
+
+
+#### Bug Fixes
+
+* **macros** makes macro errors consistent with others ([0c264a8c](https://github.com/kbknapp/clap-rs/commit/0c264a8ca57ec1cfdcb74dae79145d766cdc9b97), closes [#118](https://github.com/kbknapp/clap-rs/issues/118))
+
+#### Features
+
+* **macros**
+ * arg_enum! and simple_enum! provide a Vec<&str> of variant names ([30fa87ba](https://github.com/kbknapp/clap-rs/commit/30fa87ba4e0f3189351d8f4f78b72e616a30d0bd), closes [#119](https://github.com/kbknapp/clap-rs/issues/119))
+ * arg_enum! and simple_enum! auto-implement Display ([d1219f0d](https://github.com/kbknapp/clap-rs/commit/d1219f0d1371d872061bd0718057eca4ef47b739), closes [#120](https://github.com/kbknapp/clap-rs/issues/120))
+
+
+
+<a name="v0.8.4"></a>
+## v0.8.4 (2015-05-12)
+
+
+#### Bug Fixes
+
+* **suggestions** --help and --version now get suggestions ([d2b3b1fa](https://github.com/kbknapp/clap-rs/commit/d2b3b1faa0bdc1c5d2350cc4635aba81e02e9d96), closes [#116](https://github.com/kbknapp/clap-rs/issues/116))
+
+
+
+<a name="v0.8.3"></a>
+## v0.8.3 (2015-05-10)
+
+
+#### Bug Fixes
+
+* **usage** groups unfold their members in usage strings ([55d15582](https://github.com/kbknapp/clap-rs/commit/55d155827ea4a6b077a83669701e797ce1ad68f4), closes [#114](https://github.com/kbknapp/clap-rs/issues/114))
+
+#### Performance
+
+* **usage** removes unneeded allocations ([fd53cd18](https://github.com/kbknapp/clap-rs/commit/fd53cd188555f5c3dc8bc341c5d7eb04b761a70f))
+
+
+
+<a name="v0.8.2"></a>
+## v0.8.2 (2015-05-08)
+
+
+#### Bug Fixes
+
+* **usage strings** positional arguments are presented in index order ([eb0e374e](https://github.com/kbknapp/clap-rs/commit/eb0e374ecf952f1eefbc73113f21e0705936e40b), closes [#112](https://github.com/kbknapp/clap-rs/issues/112))
+
+
+
+<a name="v0.8.1"></a>
+## v0.8.1 (2015-05-06)
+
+
+#### Bug Fixes
+
+* **subcommands** stops parsing multiple values when subcommands are found ([fc79017e](https://github.com/kbknapp/clap-rs/commit/fc79017eced04fd41cc1801331e5054df41fac17), closes [#109](https://github.com/kbknapp/clap-rs/issues/109))
+
+#### Improvements
+
+* **color** reduces color in error messages ([aab44cca](https://github.com/kbknapp/clap-rs/commit/aab44cca6352f47e280c296e50c535f5d752dd46), closes [#110](https://github.com/kbknapp/clap-rs/issues/110))
+* **suggestions** adds suggested arguments to usage strings ([99447414](https://github.com/kbknapp/clap-rs/commit/994474146e9fb8b701af773a52da71553d74d4b7))
+
+
+
+<a name="v0.8.0"></a>
+## v0.8.0 (2015-05-06)
+
+
+#### Bug Fixes
+
+* **did-you-mean** for review ([0535cfb0](https://github.com/kbknapp/clap-rs/commit/0535cfb0c711331568b4de8080eeef80bd254b68))
+* **Positional** positionals were ignored if they matched a subcmd, even after '--' ([90e7b081](https://github.com/kbknapp/clap-rs/commit/90e7b0818741668b47cbe3becd029bab588e3553))
+* **help** fixes bug where space between arg and help is too long ([632fb115](https://github.com/kbknapp/clap-rs/commit/632fb11514c504999ea86bdce47cdd34f8ebf646))
+
+#### Features
+
+* **from_usage** adds ability to add value names or num of vals in usage string ([3d581976](https://github.com/kbknapp/clap-rs/commit/3d58197674ed7886ca315efb76e411608a327501), closes [#98](https://github.com/kbknapp/clap-rs/issues/98))
+* **did-you-mean**
+ * gate it behind 'suggestions' ([c0e38351](https://github.com/kbknapp/clap-rs/commit/c0e383515d01bdd5ca459af9c2f7e2cf49e2488b))
+ * for possible values ([1cc2deb2](https://github.com/kbknapp/clap-rs/commit/1cc2deb29158e0e4e8b434e4ce26b3d819301a7d))
+ * for long flags (i.e. --long) ([52a0b850](https://github.com/kbknapp/clap-rs/commit/52a0b8505c99354bdf5fd1cd256cf41197ac2d81))
+ * for subcommands ([06e869b5](https://github.com/kbknapp/clap-rs/commit/06e869b5180258047ed3c60ba099de818dd25fff))
+* **Flags** adds sugestions functionality ([8745071c](https://github.com/kbknapp/clap-rs/commit/8745071c3257dd327c497013516f12a823df9530))
+* **errors** colorizes output red on error ([f8b26b13](https://github.com/kbknapp/clap-rs/commit/f8b26b13da82ba3ba9a932d3d1ab4ea45d1ab036))
+
+#### Improvements
+
+* **arg_enum** allows ascii case insensitivity for enum variants ([b249f965](https://github.com/kbknapp/clap-rs/commit/b249f9657c6921c004764bd80d13ebca81585eec), closes [#104](https://github.com/kbknapp/clap-rs/issues/104))
+* **clap-test** simplified `make test` invocation ([d17dcb29](https://github.com/kbknapp/clap-rs/commit/d17dcb2920637a1f58c61c596b7bd362fd53047c))
+
+#### Documentation
+
+* **README** adds details about optional and new features ([960389de](https://github.com/kbknapp/clap-rs/commit/960389de02c9872aaee9adabe86987f71f986e39))
+* **clap** fix typos caught by codespell ([8891d929](https://github.com/kbknapp/clap-rs/commit/8891d92917aa1a069cca67272be41b99e548356e))
+* **from_usage** explains new usage strings with multiple values ([05476fc6](https://github.com/kbknapp/clap-rs/commit/05476fc61cd1e5f4a4e750d258c878732a3a9c64))
+
+
+
+<a name="v0.7.6"></a>
+## v0.7.6 (2015-05-05)
+
+
+#### Improvements
+
+* **Options** adds number of values to options in help/usage ([c1c993c4](https://github.com/kbknapp/clap-rs/commit/c1c993c419d18e35c443785053d8de9a2ef88073))
+
+#### Features
+
+* **from_usage** adds ability to add value names or num of vals in usage string ([ad55748c](https://github.com/kbknapp/clap-rs/commit/ad55748c265cf27935c7b210307d2040b6a09125), closes [#98](https://github.com/kbknapp/clap-rs/issues/98))
+
+#### Bug Fixes
+
+* **MultipleValues** properly distinguishes between multiple values and multiple occurrences ([dd2a7564](https://github.com/kbknapp/clap-rs/commit/dd2a75640ca68a91b973faad15f04df891356cef), closes [#99](https://github.com/kbknapp/clap-rs/issues/99))
+* **help** fixes tab alignment with multiple values ([847001ff](https://github.com/kbknapp/clap-rs/commit/847001ff6d8f4d9518e810fefb8edf746dd0f31e))
+
+#### Documentation
+
+* **from_usage** explains new usage strings with multiple values ([5a3a42df](https://github.com/kbknapp/clap-rs/commit/5a3a42dfa3a783537f88dedc0fd5f0edcb8ea372))
+
+
+
+<a name="v0.7.5"></a>
+## v0.7.5 (2015-05-04)
+
+
+#### Bug Fixes
+
+* **Options** fixes bug where options with no value don't error out ([a1fb94be](https://github.com/kbknapp/clap-rs/commit/a1fb94be53141572ffd97aad037295d4ffec82d0))
+
+
+
+<a name="v0.7.4"></a>
+## v0.7.4 (2015-05-03)
+
+
+#### Bug Fixes
+
+* **Options** fixes a bug where option arguments in succession get their values skipped ([f66334d0](https://github.com/kbknapp/clap-rs/commit/f66334d0ce984e2b56e5c19abb1dd536fae9342a))
+
+
+
+<a name="v0.7.3"></a>
+## v0.7.3 (2015-05-03)
+
+
+#### Bug Fixes
+
+* **RequiredValues** fixes a bug where missing values are parsed as missing arguments ([93c4a723](https://github.com/kbknapp/clap-rs/commit/93c4a7231ba1a08152648598f7aa4503ea82e4de))
+
+#### Improvements
+
+* **ErrorMessages** improves error messages and corrections ([a29c3983](https://github.com/kbknapp/clap-rs/commit/a29c3983c4229906655a29146ec15a0e46dd942d))
+* **ArgGroups** improves requirement and confliction support for groups ([c236dc5f](https://github.com/kbknapp/clap-rs/commit/c236dc5ff475110d2a1b80e62903f80296163ad3))
+
+
+
+<a name="v0.7.2"></a>
+## v0.7.2 (2015-05-03)
+
+
+#### Bug Fixes
+
+* **RequiredArgs** fixes bug where required-by-default arguments are not listed in usage ([12aea961](https://github.com/kbknapp/clap-rs/commit/12aea9612d290845ba86515c240aeeb0a21198db), closes [#96](https://github.com/kbknapp/clap-rs/issues/96))
+
+
+
+<a name="v0.7.1"></a>
+## v0.7.1 (2015-05-01)
+
+
+#### Bug Fixes
+
+* **MultipleValues** stops evaluating values if the max or exact number of values was reached ([86d92c9f](https://github.com/kbknapp/clap-rs/commit/86d92c9fdbf9f422442e9562977bbaf268dbbae1))
+
+
+
+<a name="v0.7.0"></a>
+## v0.7.0 (2015-04-30) - BREAKING CHANGE
+
+
+#### Bug Fixes
+
+* **from_usage** removes bug where usage strings have no help text ([ad4e5451](https://github.com/kbknapp/clap-rs/commit/ad4e54510739aeabf75f0da3278fb0952db531b3), closes [#83](https://github.com/kbknapp/clap-rs/issues/83))
+
+#### Features
+
+* **MultipleValues**
+ * add support for minimum and maximum number of values ([53f6b8c9](https://github.com/kbknapp/clap-rs/commit/53f6b8c9d8dc408b4fa9f833fc3a63683873c42f))
+ * adds support limited number and named values ([ae09f05e](https://github.com/kbknapp/clap-rs/commit/ae09f05e92251c1b39a83d372736fcc7b504e432))
+ * implement shorthand for options with multiple values ([6669f0a9](https://github.com/kbknapp/clap-rs/commit/6669f0a9687d4f668523145d7bd5c007d1eb59a8))
+* **arg** allow other types besides Vec for multiple value settings (**BREAKING CHANGE** [0cc2f698](https://github.com/kbknapp/clap-rs/commit/0cc2f69839b9b1db5d06330771b494783049a88e), closes [#87](https://github.com/kbknapp/clap-rs/issues/87))
+* **usage** implement smart usage strings on errors ([d77048ef](https://github.com/kbknapp/clap-rs/commit/d77048efb1e595ffe831f1a2bea2f2700db53b9f), closes [#88](https://github.com/kbknapp/clap-rs/issues/88))
+
+
+
+<a name="v0.6.9"></a>
+## v0.6.9 (2015-04-29)
+
+
+#### Bug Fixes
+
+* **from_usage** removes bug where usage strings have no help text ([ad4e5451](https://github.com/kbknapp/clap-rs/commit/ad4e54510739aeabf75f0da3278fb0952db531b3), closes [#83](https://github.com/kbknapp/clap-rs/issues/83))
+
+
+
+<a name="0.6.8"></a>
+## 0.6.8 (2015-04-27)
+
+
+#### Bug Fixes
+
+* **help** change long help --long=long -> --long <long> ([1e25abfc](https://github.com/kbknapp/clap-rs/commit/1e25abfc36679ab89eae71bf98ced4de81992d00))
+* **RequiredArgs** required by default args should no longer be required when their exclusions are present ([4bb4c3cc](https://github.com/kbknapp/clap-rs/commit/4bb4c3cc076b49e86720e882bf8c489877199f2d))
+
+#### Features
+
+* **ArgGroups** add ability to create arg groups ([09eb4d98](https://github.com/kbknapp/clap-rs/commit/09eb4d9893af40c347e50e2b717e1adef552357d))
+
+
+
+<a name="v0.6.7"></a>
+## v0.6.7 (2015-04-22)
+
+
+#### Bug Fixes
+
+* **from_usage** fix bug causing args to not be required ([b76129e9](https://github.com/kbknapp/clap-rs/commit/b76129e9b71a63365d5c77a7f57b58dbd1e94d49))
+
+#### Features
+
+* **apps** add ability to display additional help info after auto-gen'ed help msg ([65cc259e](https://github.com/kbknapp/clap-rs/commit/65cc259e4559cbe3653c865ec0c4b1e42a389b07))
+
+
+
+<a name="v0.6.6"></a>
+## v0.6.6 (2015-04-19)
+
+
+#### Bug Fixes
+
+* **from_usage** tabs and spaces should be treated equally ([4fd44181](https://github.com/kbknapp/clap-rs/commit/4fd44181d55d8eb88caab1e625231cfa3129e347))
+
+#### Features
+
+* **macros.rs** add macro to get version from Cargo.toml ([c630969a](https://github.com/kbknapp/clap-rs/commit/c630969aa3bbd386379219cae27ba1305b117f3e))
+
+
+
+<a name="v0.6.5"></a>
+## v0.6.5 (2015-04-19)
+
+
+#### Bug Fixes
+
+* **macros.rs** fix use statements for trait impls ([86e4075e](https://github.com/kbknapp/clap-rs/commit/86e4075eb111937c8a7bdb344e866e350429f042))
+
+
+
+<a name="v0.6.4"></a>
+## v0.6.4 (2015-04-17)
+
+
+#### Features
+
+* **macros** add ability to create enums pub or priv with derives ([2c499f80](https://github.com/kbknapp/clap-rs/commit/2c499f8015a199827cdf1fa3ec4f6f171722f8c7))
+
+
+
+<a name="v0.6.3"></a>
+## v0.6.3 (2015-04-16)
+
+
+#### Features
+
+* **macros** add macro to create custom enums to use as types ([fb672aff](https://github.com/kbknapp/clap-rs/commit/fb672aff561c29db2e343d6c607138f141aca8b6))
+
+
+
+<a name="v0.6.2"></a>
+## v0.6.2 (2015-04-14)
+
+
+#### Features
+
+* **macros**
+ * add ability to get multiple typed values or exit ([0b87251f](https://github.com/kbknapp/clap-rs/commit/0b87251fc088234bee51c323c2b652d7254f7a59))
+ * add ability to get a typed multiple values ([e243fe38](https://github.com/kbknapp/clap-rs/commit/e243fe38ddbbf845a46c0b9baebaac3778c80927))
+ * add convenience macro to get a typed value or exit ([4b7cd3ea](https://github.com/kbknapp/clap-rs/commit/4b7cd3ea4947780d9daa39f3e1ddab53ad4c7fef))
+ * add convenience macro to get a typed value ([8752700f](https://github.com/kbknapp/clap-rs/commit/8752700fbb30e89ee68adbce24489ae9a24d33a9))
+
+
+
+<a name="v0.6.1"></a>
+## v0.6.1 (2015-04-13)
+
+
+#### Bug Fixes
+
+* **from_usage** trim all whitespace before parsing ([91d29045](https://github.com/kbknapp/clap-rs/commit/91d2904599bd602deef2e515dfc65dc2863bdea0))
+
+
+
+<a name="v0.6.0"></a>
+## v0.6.0 (2015-04-13)
+
+
+#### Bug Fixes
+
+* **tests** fix failing doc tests ([3710cd69](https://github.com/kbknapp/clap-rs/commit/3710cd69162f87221a62464f63437c1ce843ad3c))
+
+#### Features
+
+* **app** add support for building args from usage strings ([d5d48bcf](https://github.com/kbknapp/clap-rs/commit/d5d48bcf463a4e494ef758836bd69a4c220bbbb5))
+* **args** add ability to create basic arguments from a usage string ([ab409a8f](https://github.com/kbknapp/clap-rs/commit/ab409a8f1db9e37cc70200f6f4a84a162692e618))
+
+
+
+<a name="v0.5.14"></a>
+## v0.5.14 (2015-04-10)
+
+
+#### Bug Fixes
+
+* **usage**
+ * remove unneeded space ([51372789](https://github.com/kbknapp/clap-rs/commit/5137278942121bc2593ce6e5dc224ec2682549e6))
+ * remove warning about unused variables ([ba817b9d](https://github.com/kbknapp/clap-rs/commit/ba817b9d815e37320650973f1bea0e7af3030fd7))
+
+#### Features
+
+* **usage** add ability to get usage string for subcommands too ([3636afc4](https://github.com/kbknapp/clap-rs/commit/3636afc401c2caa966efb5b1869ef4f1ed3384aa))
+
+
+
+<a name="v0.5.13"></a>
+## v0.5.13 (2015-04-09)
+
+
+#### Features
+
+* **SubCommands** add method to get name and subcommand matches together ([64e53928](https://github.com/kbknapp/clap-rs/commit/64e539280e23e567cf5de393b346eb0ca20e7eb5))
+* **ArgMatches** add method to get default usage string ([02462150](https://github.com/kbknapp/clap-rs/commit/02462150ca750bdc7012627d7e8d96379d494d7f))
+
+
+
+<a name="v0.5.12"></a>
+## v0.5.12 (2015-04-08)
+
+
+#### Features
+
+* **help** sort arguments by name so as to not display a random order ([f4b2bf57](https://github.com/kbknapp/clap-rs/commit/f4b2bf5767386013069fb74862e6e938dacf44d2))
+
+
+
+<a name="v0.5.11"></a>
+## v0.5.11 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **flags** fix bug not allowing users to specify -v or -h ([90e72cff](https://github.com/kbknapp/clap-rs/commit/90e72cffdee321b79eea7a2207119533540062b4))
+
+
+
+<a name="v0.5.10"></a>
+## v0.5.10 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **help** fix spacing when option argument has not long version ([ca17fa49](https://github.com/kbknapp/clap-rs/commit/ca17fa494b68e92da83ee364bf64b0687006824b))
+
+
+
+<a name="v0.5.9"></a>
+## v0.5.9 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **positional args** all previous positional args become required when a latter one is required ([c14c3f31](https://github.com/kbknapp/clap-rs/commit/c14c3f31fd557c165570b60911d8ee483d89d6eb), closes [#50](https://github.com/kbknapp/clap-rs/issues/50))
+* **clap** remove unstable features for Rust 1.0 ([9abdb438](https://github.com/kbknapp/clap-rs/commit/9abdb438e36e364d41550e7f5d44ebcaa8ee6b10))
+* **args** improve error messages for arguments with mutual exclusions ([18dbcf37](https://github.com/kbknapp/clap-rs/commit/18dbcf37024daf2b76ca099a6f118b53827aa339), closes [#51](https://github.com/kbknapp/clap-rs/issues/51))
+
+
+
+<a name="v0.5.8"></a>
+## v0.5.8 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **option args** fix bug in getting the wrong number of occurrences for options ([82ad6ad7](https://github.com/kbknapp/clap-rs/commit/82ad6ad77539cf9f9a03b78db466f575ebd972cc))
+* **help** fix formatting for option arguments with no long ([e8691004](https://github.com/kbknapp/clap-rs/commit/e869100423d93fa3acff03c4620cbcc0d0e790a1))
+* **flags** add assertion to catch flags with specific value sets ([a0a2a40f](https://github.com/kbknapp/clap-rs/commit/a0a2a40fed57f7c5ad9d68970d090e9856306c7d), closes [#52](https://github.com/kbknapp/clap-rs/issues/52))
+* **args** improve error messages for arguments with mutual exclusions ([bff945fc](https://github.com/kbknapp/clap-rs/commit/bff945fc5d03bba4266533340adcffb002508d1b), closes [#51](https://github.com/kbknapp/clap-rs/issues/51))
+* **tests** add missing .takes_value(true) to option2 ([bdb0e88f](https://github.com/kbknapp/clap-rs/commit/bdb0e88f696c8595c3def3bfb0e52d538c7be085))
+* **positional args** all previous positional args become required when a latter one is required ([343d47dc](https://github.com/kbknapp/clap-rs/commit/343d47dcbf83786a45c0d0f01b27fd9dd76725de), closes [#50](https://github.com/kbknapp/clap-rs/issues/50))
+
+
+
+<a name="v0.5.7"></a>
+## v0.5.7 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **args** fix bug in arguments who are required and mutually exclusive ([6ceb88a5](https://github.com/kbknapp/clap-rs/commit/6ceb88a594caae825605abc1cdad95204996bf29))
+
+
+
+<a name="v0.5.6"></a>
+## v0.5.6 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **help** fix formatting of help and usage ([28691b52](https://github.com/kbknapp/clap-rs/commit/28691b52f67e65c599e10e4ea2a0f6f9765a06b8))
+
+
+
+<a name="v0.5.5"></a>
+## v0.5.5 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **help** fix formatting of help for flags and options ([6ec10115](https://github.com/kbknapp/clap-rs/commit/6ec1011563a746f0578a93b76d45e63878e0f9a8))
+
+
+
+<a name="v0.5.4"></a>
+## v0.5.4 (2015-04-08)
+
+
+#### Features
+
+* **help** add '...' to indicate multiple values supported ([297ddba7](https://github.com/kbknapp/clap-rs/commit/297ddba77000e2228762ab0eca50b480f7467386))
+
+
+
+<a name="v0.5.3"></a>
+## v0.5.3 (2015-04-08)
+
+
+#### Features
+
+* **positionals**
+ * add assertions for positional args with multiple vals ([b7fa72d4](https://github.com/kbknapp/clap-rs/commit/b7fa72d40f18806ec2042dd67a518401c2cf5681))
+ * add support for multiple values ([80784009](https://github.com/kbknapp/clap-rs/commit/807840094109fbf90b348039ae22669ef27889ba))
+
+
+
+<a name="v0.5.2"></a>
+## v0.5.2 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **apps** allow use of hyphens in application and subcommand names ([da549dcb](https://github.com/kbknapp/clap-rs/commit/da549dcb6c7e0d773044ab17829744483a8b0f7f))
+
+
+
+<a name="v0.5.1"></a>
+## v0.5.1 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **args** determine if the only arguments allowed are also required ([0a09eb36](https://github.com/kbknapp/clap-rs/commit/0a09eb365ced9a03faf8ed24f083ef730acc90e8))
+
+
+
+<a name="v0.5.0"></a>
+## v0.5.0 (2015-04-08)
+
+
+#### Features
+
+* **args** add support for a specific set of allowed values on options or positional arguments ([270eb889](https://github.com/kbknapp/clap-rs/commit/270eb88925b6dc2881bff1f31ee344f085d31809))
+
+
+
+<a name="v0.4.18"></a>
+## v0.4.18 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **usage** display required args in usage, even if only required by others ([1b7316d4](https://github.com/kbknapp/clap-rs/commit/1b7316d4a8df70b0aa584ccbfd33f68966ad2a54))
+
+#### Features
+
+* **subcommands** properly list subcommands in help and usage ([4ee02344](https://github.com/kbknapp/clap-rs/commit/4ee023442abc3dba54b68138006a52b714adf331))
+
+
+
+<a name="v0.4.17"></a>
+## v0.4.17 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **tests** remove cargo test from claptests makefile ([1cf73817](https://github.com/kbknapp/clap-rs/commit/1cf73817d6fb1dccb5b6a23b46c2efa8b567ad62))
+
+
+
+<a name="v0.4.16"></a>
+## v0.4.16 (2015-04-08)
+
+
+#### Bug Fixes
+
+* **option** fix bug with option occurrence values ([9af52e93](https://github.com/kbknapp/clap-rs/commit/9af52e93cef9e17ac9974963f132013d0b97b946))
+* **tests** fix testing script bug and formatting ([d8f03a55](https://github.com/kbknapp/clap-rs/commit/d8f03a55c4f74d126710ee06aad5a667246a8001))
+
+#### Features
+
+* **arg** allow lifetimes other than 'static in arguments ([9e8c1fb9](https://github.com/kbknapp/clap-rs/commit/9e8c1fb9406f8448873ca58bab07fe905f1551e5))
diff --git a/clap/CONTRIBUTORS.md b/clap/CONTRIBUTORS.md
new file mode 100644
index 0000000..f0fd777
--- /dev/null
+++ b/clap/CONTRIBUTORS.md
@@ -0,0 +1,91 @@
+the following is a list of contributors:
+
+
+[<img alt="kbknapp" src="https://avatars1.githubusercontent.com/u/6942134?v=4&s=117" width="117">](https://github.com/kbknapp) |[<img alt="homu" src="https://avatars1.githubusercontent.com/u/10212162?v=4&s=117" width="117">](https://github.com/homu) |[<img alt="Vinatorul" src="https://avatars1.githubusercontent.com/u/6770624?v=4&s=117" width="117">](https://github.com/Vinatorul) |[<img alt="tormol" src="https://avatars3.githubusercontent.com/u/10460821?v=4&s=117" width="117">](https://github.com/tormol) |[<img alt="willmurphyscode" src="https://avatars3.githubusercontent.com/u/12529630?v=4&s=117" width="117">](https://github.com/willmurphyscode) |[<img alt="little-dude" src="https://avatars2.githubusercontent.com/u/6646324?v=4&s=117" width="117">](https://github.com/little-dude) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[willmurphyscode](https://github.com/willmurphyscode) |[little-dude](https://github.com/little-dude) |
+
+[<img alt="sru" src="https://avatars3.githubusercontent.com/u/2485892?v=4&s=117" width="117">](https://github.com/sru) |[<img alt="mgeisler" src="https://avatars0.githubusercontent.com/u/89623?v=4&s=117" width="117">](https://github.com/mgeisler) |[<img alt="nabijaczleweli" src="https://avatars3.githubusercontent.com/u/6709544?v=4&s=117" width="117">](https://github.com/nabijaczleweli) |[<img alt="Byron" src="https://avatars2.githubusercontent.com/u/63622?v=4&s=117" width="117">](https://github.com/Byron) |[<img alt="hgrecco" src="https://avatars0.githubusercontent.com/u/278566?v=4&s=117" width="117">](https://github.com/hgrecco) |[<img alt="bluejekyll" src="https://avatars3.githubusercontent.com/u/986845?v=4&s=117" width="117">](https://github.com/bluejekyll) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[sru](https://github.com/sru) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) |
+
+[<img alt="segevfiner" src="https://avatars0.githubusercontent.com/u/24731903?v=4&s=117" width="117">](https://github.com/segevfiner) |[<img alt="ignatenkobrain" src="https://avatars1.githubusercontent.com/u/2866862?v=4&s=117" width="117">](https://github.com/ignatenkobrain) |[<img alt="james-darkfox" src="https://avatars3.githubusercontent.com/u/637155?v=4&s=117" width="117">](https://github.com/james-darkfox) |[<img alt="H2CO3" src="https://avatars2.githubusercontent.com/u/742370?v=4&s=117" width="117">](https://github.com/H2CO3) |[<img alt="nateozem" src="https://avatars2.githubusercontent.com/u/22719441?v=4&s=117" width="117">](https://github.com/nateozem) |[<img alt="glowing-chemist" src="https://avatars0.githubusercontent.com/u/17074682?v=4&s=117" width="117">](https://github.com/glowing-chemist) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[segevfiner](https://github.com/segevfiner) |[ignatenkobrain](https://github.com/ignatenkobrain) |[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) |
+
+[<img alt="discosultan" src="https://avatars1.githubusercontent.com/u/2970736?v=4&s=117" width="117">](https://github.com/discosultan) |[<img alt="rtaycher" src="https://avatars0.githubusercontent.com/u/324733?v=4&s=117" width="117">](https://github.com/rtaycher) |[<img alt="Arnavion" src="https://avatars2.githubusercontent.com/u/1096010?v=4&s=117" width="117">](https://github.com/Arnavion) |[<img alt="japaric" src="https://avatars3.githubusercontent.com/u/5018213?v=4&s=117" width="117">](https://github.com/japaric) |[<img alt="untitaker" src="https://avatars0.githubusercontent.com/u/837573?v=4&s=117" width="117">](https://github.com/untitaker) |[<img alt="afiune" src="https://avatars0.githubusercontent.com/u/5712253?v=4&s=117" width="117">](https://github.com/afiune) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[discosultan](https://github.com/discosultan) |[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) |
+
+[<img alt="crazymerlyn" src="https://avatars1.githubusercontent.com/u/6919679?v=4&s=117" width="117">](https://github.com/crazymerlyn) |[<img alt="SuperFluffy" src="https://avatars0.githubusercontent.com/u/701177?v=4&s=117" width="117">](https://github.com/SuperFluffy) |[<img alt="matthiasbeyer" src="https://avatars0.githubusercontent.com/u/427866?v=4&s=117" width="117">](https://github.com/matthiasbeyer) |[<img alt="malbarbo" src="https://avatars3.githubusercontent.com/u/1678126?v=4&s=117" width="117">](https://github.com/malbarbo) |[<img alt="tshepang" src="https://avatars0.githubusercontent.com/u/588486?v=4&s=117" width="117">](https://github.com/tshepang) |[<img alt="golem131" src="https://avatars3.githubusercontent.com/u/2429587?v=4&s=117" width="117">](https://github.com/golem131) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) |
+
+[<img alt="jimmycuadra" src="https://avatars2.githubusercontent.com/u/122457?v=4&s=117" width="117">](https://github.com/jimmycuadra) |[<img alt="Nemo157" src="https://avatars1.githubusercontent.com/u/81079?v=4&s=117" width="117">](https://github.com/Nemo157) |[<img alt="severen" src="https://avatars1.githubusercontent.com/u/4061736?v=4&s=117" width="117">](https://github.com/severen) |[<img alt="Eijebong" src="https://avatars2.githubusercontent.com/u/3650385?v=4&s=117" width="117">](https://github.com/Eijebong) |[<img alt="cstorey" src="https://avatars3.githubusercontent.com/u/743059?v=4&s=117" width="117">](https://github.com/cstorey) |[<img alt="wdv4758h" src="https://avatars1.githubusercontent.com/u/2716047?v=4&s=117" width="117">](https://github.com/wdv4758h) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) |
+
+[<img alt="frewsxcv" src="https://avatars2.githubusercontent.com/u/416575?v=4&s=117" width="117">](https://github.com/frewsxcv) |[<img alt="hoodie" src="https://avatars1.githubusercontent.com/u/260370?v=4&s=117" width="117">](https://github.com/hoodie) |[<img alt="huonw" src="https://avatars1.githubusercontent.com/u/1203825?v=4&s=117" width="117">](https://github.com/huonw) |[<img alt="GrappigPanda" src="https://avatars0.githubusercontent.com/u/2055372?v=4&s=117" width="117">](https://github.com/GrappigPanda) |[<img alt="shepmaster" src="https://avatars0.githubusercontent.com/u/174509?v=4&s=117" width="117">](https://github.com/shepmaster) |[<img alt="starkat99" src="https://avatars1.githubusercontent.com/u/8295111?v=4&s=117" width="117">](https://github.com/starkat99) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) |
+
+[<img alt="porglezomp" src="https://avatars1.githubusercontent.com/u/1690225?v=4&s=117" width="117">](https://github.com/porglezomp) |[<img alt="kraai" src="https://avatars1.githubusercontent.com/u/552646?v=4&s=117" width="117">](https://github.com/kraai) |[<img alt="musoke" src="https://avatars0.githubusercontent.com/u/16665084?v=4&s=117" width="117">](https://github.com/musoke) |[<img alt="nelsonjchen" src="https://avatars1.githubusercontent.com/u/5363?v=4&s=117" width="117">](https://github.com/nelsonjchen) |[<img alt="pkgw" src="https://avatars0.githubusercontent.com/u/59598?v=4&s=117" width="117">](https://github.com/pkgw) |[<img alt="Deedasmi" src="https://avatars0.githubusercontent.com/u/5093293?v=4&s=117" width="117">](https://github.com/Deedasmi) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[porglezomp](https://github.com/porglezomp) |[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) |
+
+[<img alt="vmchale" src="https://avatars1.githubusercontent.com/u/13259982?v=4&s=117" width="117">](https://github.com/vmchale) |[<img alt="etopiei" src="https://avatars3.githubusercontent.com/u/17671663?v=4&s=117" width="117">](https://github.com/etopiei) |[<img alt="messense" src="https://avatars0.githubusercontent.com/u/1556054?v=4&s=117" width="117">](https://github.com/messense) |[<img alt="Keats" src="https://avatars2.githubusercontent.com/u/680355?v=4&s=117" width="117">](https://github.com/Keats) |[<img alt="kieraneglin" src="https://avatars0.githubusercontent.com/u/569917?v=4&s=117" width="117">](https://github.com/kieraneglin) |[<img alt="durka" src="https://avatars3.githubusercontent.com/u/47007?v=4&s=117" width="117">](https://github.com/durka) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[vmchale](https://github.com/vmchale) |[etopiei](https://github.com/etopiei) |[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) |
+
+[<img alt="alex-gulyas" src="https://avatars0.githubusercontent.com/u/8698329?v=4&s=117" width="117">](https://github.com/alex-gulyas) |[<img alt="cite-reader" src="https://avatars1.githubusercontent.com/u/4196987?v=4&s=117" width="117">](https://github.com/cite-reader) |[<img alt="alexbool" src="https://avatars3.githubusercontent.com/u/1283792?v=4&s=117" width="117">](https://github.com/alexbool) |[<img alt="AluisioASG" src="https://avatars2.githubusercontent.com/u/1904165?v=4&s=117" width="117">](https://github.com/AluisioASG) |[<img alt="BurntSushi" src="https://avatars3.githubusercontent.com/u/456674?v=4&s=117" width="117">](https://github.com/BurntSushi) |[<img alt="AndrewGaspar" src="https://avatars1.githubusercontent.com/u/2292643?v=4&s=117" width="117">](https://github.com/AndrewGaspar) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[AndrewGaspar](https://github.com/AndrewGaspar) |
+
+[<img alt="nox" src="https://avatars0.githubusercontent.com/u/123095?v=4&s=117" width="117">](https://github.com/nox) |[<img alt="mitsuhiko" src="https://avatars1.githubusercontent.com/u/7396?v=4&s=117" width="117">](https://github.com/mitsuhiko) |[<img alt="pixelistik" src="https://avatars1.githubusercontent.com/u/170929?v=4&s=117" width="117">](https://github.com/pixelistik) |[<img alt="ogham" src="https://avatars3.githubusercontent.com/u/503760?v=4&s=117" width="117">](https://github.com/ogham) |[<img alt="Bilalh" src="https://avatars0.githubusercontent.com/u/171602?v=4&s=117" width="117">](https://github.com/Bilalh) |[<img alt="dotdash" src="https://avatars1.githubusercontent.com/u/230962?v=4&s=117" width="117">](https://github.com/dotdash) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) |[pixelistik](https://github.com/pixelistik) |[ogham](https://github.com/ogham) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) |
+
+[<img alt="bradurani" src="https://avatars0.githubusercontent.com/u/4195952?v=4&s=117" width="117">](https://github.com/bradurani) |[<img alt="Seeker14491" src="https://avatars2.githubusercontent.com/u/6490497?v=4&s=117" width="117">](https://github.com/Seeker14491) |[<img alt="brianp" src="https://avatars1.githubusercontent.com/u/179134?v=4&s=117" width="117">](https://github.com/brianp) |[<img alt="cldershem" src="https://avatars3.githubusercontent.com/u/201608?v=4&s=117" width="117">](https://github.com/cldershem) |[<img alt="casey" src="https://avatars2.githubusercontent.com/u/1945?v=4&s=117" width="117">](https://github.com/casey) |[<img alt="volks73" src="https://avatars1.githubusercontent.com/u/1915469?v=4&s=117" width="117">](https://github.com/volks73) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) |[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) |
+
+[<img alt="daboross" src="https://avatars1.githubusercontent.com/u/1152146?v=4&s=117" width="117">](https://github.com/daboross) |[<img alt="da-x" src="https://avatars1.githubusercontent.com/u/321273?v=4&s=117" width="117">](https://github.com/da-x) |[<img alt="mernen" src="https://avatars0.githubusercontent.com/u/6412?v=4&s=117" width="117">](https://github.com/mernen) |[<img alt="dguo" src="https://avatars0.githubusercontent.com/u/2763135?v=4&s=117" width="117">](https://github.com/dguo) |[<img alt="davidszotten" src="https://avatars3.githubusercontent.com/u/412005?v=4&s=117" width="117">](https://github.com/davidszotten) |[<img alt="drusellers" src="https://avatars1.githubusercontent.com/u/63355?v=4&s=117" width="117">](https://github.com/drusellers) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[daboross](https://github.com/daboross) |[da-x](https://github.com/da-x) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) |
+
+[<img alt="eddyb" src="https://avatars2.githubusercontent.com/u/77424?v=4&s=117" width="117">](https://github.com/eddyb) |[<img alt="Enet4" src="https://avatars0.githubusercontent.com/u/4738426?v=4&s=117" width="117">](https://github.com/Enet4) |[<img alt="Fraser999" src="https://avatars3.githubusercontent.com/u/190532?v=4&s=117" width="117">](https://github.com/Fraser999) |[<img alt="birkenfeld" src="https://avatars0.githubusercontent.com/u/144359?v=4&s=117" width="117">](https://github.com/birkenfeld) |[<img alt="guanqun" src="https://avatars0.githubusercontent.com/u/53862?v=4&s=117" width="117">](https://github.com/guanqun) |[<img alt="tanakh" src="https://avatars2.githubusercontent.com/u/109069?v=4&s=117" width="117">](https://github.com/tanakh) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) |
+
+[<img alt="SirVer" src="https://avatars0.githubusercontent.com/u/140115?v=4&s=117" width="117">](https://github.com/SirVer) |[<img alt="idmit" src="https://avatars1.githubusercontent.com/u/2546728?v=4&s=117" width="117">](https://github.com/idmit) |[<img alt="archer884" src="https://avatars1.githubusercontent.com/u/679494?v=4&s=117" width="117">](https://github.com/archer884) |[<img alt="jacobmischka" src="https://avatars1.githubusercontent.com/u/3939997?v=4&s=117" width="117">](https://github.com/jacobmischka) |[<img alt="jespino" src="https://avatars0.githubusercontent.com/u/290303?v=4&s=117" width="117">](https://github.com/jespino) |[<img alt="jfrankenau" src="https://avatars3.githubusercontent.com/u/2736480?v=4&s=117" width="117">](https://github.com/jfrankenau) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) |
+
+[<img alt="jtdowney" src="https://avatars1.githubusercontent.com/u/44654?v=4&s=117" width="117">](https://github.com/jtdowney) |[<img alt="andete" src="https://avatars2.githubusercontent.com/u/689017?v=4&s=117" width="117">](https://github.com/andete) |[<img alt="joshtriplett" src="https://avatars2.githubusercontent.com/u/162737?v=4&s=117" width="117">](https://github.com/joshtriplett) |[<img alt="Kalwyn" src="https://avatars3.githubusercontent.com/u/22778640?v=4&s=117" width="117">](https://github.com/Kalwyn) |[<img alt="manuel-rhdt" src="https://avatars1.githubusercontent.com/u/3199013?v=4&s=117" width="117">](https://github.com/manuel-rhdt) |[<img alt="Marwes" src="https://avatars3.githubusercontent.com/u/957312?v=4&s=117" width="117">](https://github.com/Marwes) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) |
+
+[<img alt="mdaffin" src="https://avatars1.githubusercontent.com/u/171232?v=4&s=117" width="117">](https://github.com/mdaffin) |[<img alt="iliekturtles" src="https://avatars3.githubusercontent.com/u/5081378?v=4&s=117" width="117">](https://github.com/iliekturtles) |[<img alt="nicompte" src="https://avatars2.githubusercontent.com/u/439369?v=4&s=117" width="117">](https://github.com/nicompte) |[<img alt="NickeZ" src="https://avatars2.githubusercontent.com/u/492753?v=4&s=117" width="117">](https://github.com/NickeZ) |[<img alt="nvzqz" src="https://avatars0.githubusercontent.com/u/10367662?v=4&s=117" width="117">](https://github.com/nvzqz) |[<img alt="nuew" src="https://avatars2.githubusercontent.com/u/26099511?v=4&s=117" width="117">](https://github.com/nuew) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) |
+
+[<img alt="Geogi" src="https://avatars1.githubusercontent.com/u/1818316?v=4&s=117" width="117">](https://github.com/Geogi) |[<img alt="focusaurus" src="https://avatars1.githubusercontent.com/u/482377?v=4&s=117" width="117">](https://github.com/focusaurus) |[<img alt="flying-sheep" src="https://avatars0.githubusercontent.com/u/291575?v=4&s=117" width="117">](https://github.com/flying-sheep) |[<img alt="Phlosioneer" src="https://avatars2.githubusercontent.com/u/4657718?v=4&s=117" width="117">](https://github.com/Phlosioneer) |[<img alt="peppsac" src="https://avatars3.githubusercontent.com/u/2198295?v=4&s=117" width="117">](https://github.com/peppsac) |[<img alt="golddranks" src="https://avatars1.githubusercontent.com/u/2675542?v=4&s=117" width="117">](https://github.com/golddranks) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) |
+
+[<img alt="hexjelly" src="https://avatars0.githubusercontent.com/u/435283?v=4&s=117" width="117">](https://github.com/hexjelly) |[<img alt="rom1v" src="https://avatars1.githubusercontent.com/u/543275?v=4&s=117" width="117">](https://github.com/rom1v) |[<img alt="rnelson" src="https://avatars3.githubusercontent.com/u/118361?v=4&s=117" width="117">](https://github.com/rnelson) |[<img alt="swatteau" src="https://avatars3.githubusercontent.com/u/5521255?v=4&s=117" width="117">](https://github.com/swatteau) |[<img alt="tchajed" src="https://avatars3.githubusercontent.com/u/1255037?v=4&s=117" width="117">](https://github.com/tchajed) |[<img alt="tspiteri" src="https://avatars0.githubusercontent.com/u/18604588?v=4&s=117" width="117">](https://github.com/tspiteri) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) |[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tchajed](https://github.com/tchajed) |[tspiteri](https://github.com/tspiteri) |
+
+[<img alt="siiptuo" src="https://avatars0.githubusercontent.com/u/10729330?v=4&s=117" width="117">](https://github.com/siiptuo) |[<img alt="vks" src="https://avatars2.githubusercontent.com/u/33460?v=4&s=117" width="117">](https://github.com/vks) |[<img alt="vsupalov" src="https://avatars2.githubusercontent.com/u/2801030?v=4&s=117" width="117">](https://github.com/vsupalov) |[<img alt="mineo" src="https://avatars1.githubusercontent.com/u/78236?v=4&s=117" width="117">](https://github.com/mineo) |[<img alt="wabain" src="https://avatars3.githubusercontent.com/u/7651435?v=4&s=117" width="117">](https://github.com/wabain) |[<img alt="grossws" src="https://avatars2.githubusercontent.com/u/171284?v=4&s=117" width="117">](https://github.com/grossws) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) |
+
+[<img alt="kennytm" src="https://avatars1.githubusercontent.com/u/103023?v=4&s=117" width="117">](https://github.com/kennytm) |[<img alt="king6cong" src="https://avatars3.githubusercontent.com/u/302560?v=4&s=117" width="117">](https://github.com/king6cong) |[<img alt="mvaude" src="https://avatars1.githubusercontent.com/u/9532611?v=4&s=117" width="117">](https://github.com/mvaude) |[<img alt="panicbit" src="https://avatars2.githubusercontent.com/u/628445?v=4&s=117" width="117">](https://github.com/panicbit) |[<img alt="brennie" src="https://avatars3.githubusercontent.com/u/156585?v=4&s=117" width="117">](https://github.com/brennie) |
+:---: |:---: |:---: |:---: |:---: |
+[kennytm](https://github.com/kennytm) |[king6cong](https://github.com/king6cong) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[brennie](https://github.com/brennie) |
+
+
+
+
+This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list)
diff --git a/clap/Cargo.toml b/clap/Cargo.toml
new file mode 100644
index 0000000..47498c1
--- /dev/null
+++ b/clap/Cargo.toml
@@ -0,0 +1,91 @@
+[package]
+
+name = "clap"
+version = "2.33.0"
+authors = ["Kevin K. <kbknapp@gmail.com>"]
+exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
+repository = "https://github.com/clap-rs/clap"
+documentation = "https://docs.rs/clap/"
+homepage = "https://clap.rs/"
+readme = "README.md"
+license = "MIT"
+keywords = ["argument", "cli", "arg", "parser", "parse"]
+categories = ["command-line-interface"]
+description = """
+A simple to use, efficient, and full-featured Command Line Argument Parser
+"""
+
+[badges]
+travis-ci = { repository = "clap-rs/clap" }
+appveyor = { repository = "clap-rs/clap" }
+coveralls = { repository = "clap-rs/clap", branch = "master" }
+is-it-maintained-issue-resolution = { repository = "clap-rs/clap" }
+is-it-maintained-open-issues = { repository = "clap-rs/clap" }
+maintenance = {status = "actively-developed"}
+
+[dependencies]
+bitflags = "1.0"
+unicode-width = "0.1.4"
+textwrap = "0.11.0"
+strsim = { version = "0.8", optional = true }
+yaml-rust = { version = "0.3.5", optional = true }
+clippy = { version = "~0.0.166", optional = true }
+atty = { version = "0.2.2", optional = true }
+vec_map = { version = "0.8", optional = true }
+term_size = { version = "0.3.0", optional = true }
+
+[target.'cfg(not(windows))'.dependencies]
+ansi_term = { version = "0.11", optional = true }
+
+[dev-dependencies]
+regex = "1"
+lazy_static = "1.3"
+version-sync = "0.8"
+
+[features]
+default = ["suggestions", "color", "vec_map"]
+suggestions = ["strsim"]
+color = ["ansi_term", "atty"]
+wrap_help = ["term_size", "textwrap/term_size"]
+yaml = ["yaml-rust"]
+unstable = [] # for building with unstable clap features (doesn't require nightly Rust) (currently none)
+nightly = [] # for building with unstable Rust features (currently none)
+lints = ["clippy"] # Requires nightly Rust
+debug = [] # Enables debug messages
+no_cargo = [] # Enable if you're not using Cargo, disables Cargo-env-var-dependent macros
+doc = ["yaml"] # All the features which add to documentation
+
+[profile.release]
+opt-level = 3
+debug = false
+rpath = false
+lto = true
+debug-assertions = false
+codegen-units = 1
+
+[profile.dev]
+opt-level = 0
+debug = true
+rpath = false
+lto = false
+debug-assertions = true
+codegen-units = 4
+
+[profile.test]
+opt-level = 1
+debug = true
+rpath = false
+lto = false
+debug-assertions = true
+codegen-units = 4
+
+[profile.bench]
+opt-level = 3
+debug = false
+rpath = false
+lto = true
+debug-assertions = false
+codegen-units = 1
+
+[package.metadata.docs.rs]
+features = ["doc"]
diff --git a/clap/LICENSE-MIT b/clap/LICENSE-MIT
new file mode 100644
index 0000000..5acedf0
--- /dev/null
+++ b/clap/LICENSE-MIT
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-2016 Kevin B. Knapp
+
+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/clap/README.md b/clap/README.md
new file mode 100644
index 0000000..c95f494
--- /dev/null
+++ b/clap/README.md
@@ -0,0 +1,542 @@
+clap
+====
+
+[![Crates.io](https://img.shields.io/crates/v/clap.svg)](https://crates.io/crates/clap) [![Crates.io](https://img.shields.io/crates/d/clap.svg)](https://crates.io/crates/clap) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/clap-rs/clap/blob/master/LICENSE-MIT) [![Coverage Status](https://coveralls.io/repos/kbknapp/clap-rs/badge.svg?branch=master&service=github)](https://coveralls.io/github/kbknapp/clap-rs?branch=master) [![Join the chat at https://gitter.im/kbknapp/clap-rs](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/kbknapp/clap-rs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+Linux: [![Build Status](https://travis-ci.org/clap-rs/clap.svg?branch=master)](https://travis-ci.org/clap-rs/clap)
+Windows: [![Build status](https://ci.appveyor.com/api/projects/status/ejg8c33dn31nhv36/branch/master?svg=true)](https://ci.appveyor.com/project/kbknapp/clap-rs/branch/master)
+
+Command Line Argument Parser for Rust
+
+It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcommands when writing console/terminal applications.
+
+* [documentation](https://docs.rs/clap/)
+* [website](https://clap.rs/)
+* [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U)
+
+Table of Contents
+=================
+
+* [About](#about)
+* [FAQ](#faq)
+* [Features](#features)
+* [Quick Example](#quick-example)
+* [Try it!](#try-it)
+ * [Pre-Built Test](#pre-built-test)
+ * [BYOB (Build Your Own Binary)](#byob-build-your-own-binary)
+* [Usage](#usage)
+ * [Optional Dependencies / Features](#optional-dependencies--features)
+ * [Dependencies Tree](#dependencies-tree)
+ * [More Information](#more-information)
+ * [Video Tutorials](#video-tutorials)
+* [How to Contribute](#how-to-contribute)
+ * [Compatibility Policy](#compatibility-policy)
+ * [Minimum Version of Rust](#minimum-version-of-rust)
+* [Related Crates](#related-crates)
+* [License](#license)
+* [Recent Breaking Changes](#recent-breaking-changes)
+ * [Deprecations](#deprecations)
+
+Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
+
+## About
+
+`clap` is used to parse *and validate* the string of command line arguments provided by a user at runtime. You provide the list of valid possibilities, and `clap` handles the rest. This means you focus on your *applications* functionality, and less on the parsing and validating of arguments.
+
+`clap` provides many things 'for free' (with no configuration) including the traditional version and help switches (or flags) along with associated messages. If you are using subcommands, `clap` will also auto-generate a `help` subcommand and separate associated help messages.
+
+Once `clap` parses the user provided string of arguments, it returns the matches along with any applicable values. If the user made an error or typo, `clap` informs them with a friendly message and exits gracefully (or returns a `Result` type and allows you to perform any clean up prior to exit). Because of this, you can make reasonable assumptions in your code about the validity of the arguments prior to your applications main execution.
+
+## FAQ
+
+For a full FAQ and more in depth details, see [the wiki page](https://github.com/clap-rs/clap/wiki/FAQ)
+
+### Comparisons
+
+First, let me say that these comparisons are highly subjective, and not meant in a critical or harsh manner. All the argument parsing libraries out there (to include `clap`) have their own strengths and weaknesses. Sometimes it just comes down to personal taste when all other factors are equal. When in doubt, try them all and pick one that you enjoy :) There's plenty of room in the Rust community for multiple implementations!
+
+#### How does `clap` compare to [getopts](https://github.com/rust-lang-nursery/getopts)?
+
+`getopts` is a very basic, fairly minimalist argument parsing library. This isn't a bad thing, sometimes you don't need tons of features, you just want to parse some simple arguments, and have some help text generated for you based on valid arguments you specify. The downside to this approach is that you must manually implement most of the common features (such as checking to display help messages, usage strings, etc.). If you want a highly custom argument parser, and don't mind writing the majority of the functionality yourself, `getopts` is an excellent base.
+
+`getopts` also doesn't allocate much, or at all. This gives it a very small performance boost. Although, as you start implementing additional features, that boost quickly disappears.
+
+Personally, I find many, many uses of `getopts` are manually implementing features that `clap` provides by default. Using `clap` simplifies your codebase allowing you to focus on your application, and not argument parsing.
+
+#### How does `clap` compare to [docopt.rs](https://github.com/docopt/docopt.rs)?
+
+I first want to say I'm a big a fan of BurntSushi's work, the creator of `Docopt.rs`. I aspire to produce the quality of libraries that this man does! When it comes to comparing these two libraries they are very different. `docopt` tasks you with writing a help message, and then it parsers that message for you to determine all valid arguments and their use. Some people LOVE this approach, others do not. If you're willing to write a detailed help message, it's nice that you can stick that in your program and have `docopt` do the rest. On the downside, it's far less flexible.
+
+`docopt` is also excellent at translating arguments into Rust types automatically. There is even a syntax extension which will do all this for you, if you're willing to use a nightly compiler (use of a stable compiler requires you to somewhat manually translate from arguments to Rust types). To use BurntSushi's words, `docopt` is also a sort of black box. You get what you get, and it's hard to tweak implementation or customize the experience for your use case.
+
+Because `docopt` is doing a ton of work to parse your help messages and determine what you were trying to communicate as valid arguments, it's also one of the more heavy weight parsers performance-wise. For most applications this isn't a concern and this isn't to say `docopt` is slow, in fact far from it. This is just something to keep in mind while comparing.
+
+#### All else being equal, what are some reasons to use `clap`? (The Pitch)
+
+`clap` is as fast, and as lightweight as possible while still giving all the features you'd expect from a modern argument parser. In fact, for the amount and type of features `clap` offers it remains about as fast as `getopts`. If you use `clap` when just need some simple arguments parsed, you'll find it's a walk in the park. `clap` also makes it possible to represent extremely complex, and advanced requirements, without too much thought. `clap` aims to be intuitive, easy to use, and fully capable for wide variety use cases and needs.
+
+#### All else being equal, what are some reasons *not* to use `clap`? (The Anti Pitch)
+
+Depending on the style in which you choose to define the valid arguments, `clap` can be very verbose. `clap` also offers so many fine-tuning knobs and dials, that learning everything can seem overwhelming. I strive to keep the simple cases simple, but when turning all those custom dials it can get complex. `clap` is also opinionated about parsing. Even though so much can be tweaked and tuned with `clap` (and I'm adding more all the time), there are still certain features which `clap` implements in specific ways which may be contrary to some users use-cases. Finally, `clap` is "stringly typed" when referring to arguments which can cause typos in code. This particular paper-cut is being actively worked on, and should be gone in v3.x.
+
+## Features
+
+Below are a few of the features which `clap` supports, full descriptions and usage can be found in the [documentation](https://docs.rs/clap/) and [examples/](examples) directory
+
+* **Auto-generated Help, Version, and Usage information**
+ - Can optionally be fully, or partially overridden if you want a custom help, version, or usage statements
+* **Auto-generated completion scripts at compile time (Bash, Zsh, Fish, and PowerShell)**
+ - Even works through many multiple levels of subcommands
+ - Works with options which only accept certain values
+ - Works with subcommand aliases
+* **Flags / Switches** (i.e. bool fields)
+ - Both short and long versions supported (i.e. `-f` and `--flag` respectively)
+ - Supports combining short versions (i.e. `-fBgoZ` is the same as `-f -B -g -o -Z`)
+ - Supports multiple occurrences (i.e. `-vvv` or `-v -v -v`)
+* **Positional Arguments** (i.e. those which are based off an index from the program name)
+ - Supports multiple values (i.e. `myprog <file>...` such as `myprog file1.txt file2.txt` being two values for the same "file" argument)
+ - Supports Specific Value Sets (See below)
+ - Can set value parameters (such as the minimum number of values, the maximum number of values, or the exact number of values)
+ - Can set custom validations on values to extend the argument parsing capability to truly custom domains
+* **Option Arguments** (i.e. those that take values)
+ - Both short and long versions supported (i.e. `-o value`, `-ovalue`, `-o=value` and `--option value` or `--option=value` respectively)
+ - Supports multiple values (i.e. `-o <val1> -o <val2>` or `-o <val1> <val2>`)
+ - Supports delimited values (i.e. `-o=val1,val2,val3`, can also change the delimiter)
+ - Supports Specific Value Sets (See below)
+ - Supports named values so that the usage/help info appears as `-o <FILE> <INTERFACE>` etc. for when you require specific multiple values
+ - Can set value parameters (such as the minimum number of values, the maximum number of values, or the exact number of values)
+ - Can set custom validations on values to extend the argument parsing capability to truly custom domains
+* **Sub-Commands** (i.e. `git add <file>` where `add` is a sub-command of `git`)
+ - Support their own sub-arguments, and sub-sub-commands independent of the parent
+ - Get their own auto-generated Help, Version, and Usage independent of parent
+* **Support for building CLIs from YAML** - This keeps your Rust source nice and tidy and makes supporting localized translation very simple!
+* **Requirement Rules**: Arguments can define the following types of requirement rules
+ - Can be required by default
+ - Can be required only if certain arguments are present
+ - Can require other arguments to be present
+ - Can be required only if certain values of other arguments are used
+* **Confliction Rules**: Arguments can optionally define the following types of exclusion rules
+ - Can be disallowed when certain arguments are present
+ - Can disallow use of other arguments when present
+* **Groups**: Arguments can be made part of a group
+ - Fully compatible with other relational rules (requirements, conflicts, and overrides) which allows things like requiring the use of any arg in a group, or denying the use of an entire group conditionally
+* **Specific Value Sets**: Positional or Option Arguments can define a specific set of allowed values (i.e. imagine a `--mode` option which may *only* have one of two values `fast` or `slow` such as `--mode fast` or `--mode slow`)
+* **Default Values**
+ - Also supports conditional default values (i.e. a default which only applies if specific arguments are used, or specific values of those arguments)
+* **Automatic Version from Cargo.toml**: `clap` is fully compatible with Rust's `env!()` macro for automatically setting the version of your application to the version in your Cargo.toml. See [09_auto_version example](examples/09_auto_version.rs) for how to do this (Thanks to [jhelwig](https://github.com/jhelwig) for pointing this out)
+* **Typed Values**: You can use several convenience macros provided by `clap` to get typed values (i.e. `i32`, `u8`, etc.) from positional or option arguments so long as the type you request implements `std::str::FromStr` See the [12_typed_values example](examples/12_typed_values.rs). You can also use `clap`s `arg_enum!` macro to create an enum with variants that automatically implement `std::str::FromStr`. See [13a_enum_values_automatic example](examples/13a_enum_values_automatic.rs) for details
+* **Suggestions**: Suggests corrections when the user enters a typo. For example, if you defined a `--myoption` argument, and the user mistakenly typed `--moyption` (notice `y` and `o` transposed), they would receive a `Did you mean '--myoption'?` error and exit gracefully. This also works for subcommands and flags. (Thanks to [Byron](https://github.com/Byron) for the implementation) (This feature can optionally be disabled, see 'Optional Dependencies / Features')
+* **Colorized Errors (Non Windows OS only)**: Error message are printed in in colored text (this feature can optionally be disabled, see 'Optional Dependencies / Features').
+* **Global Arguments**: Arguments can optionally be defined once, and be available to all child subcommands. There values will also be propagated up/down throughout all subcommands.
+* **Custom Validations**: You can define a function to use as a validator of argument values. Imagine defining a function to validate IP addresses, or fail parsing upon error. This means your application logic can be solely focused on *using* values.
+* **POSIX Compatible Conflicts/Overrides** - In POSIX args can be conflicting, but not fail parsing because whichever arg comes *last* "wins" so to speak. This allows things such as aliases (i.e. `alias ls='ls -l'` but then using `ls -C` in your terminal which ends up passing `ls -l -C` as the final arguments. Since `-l` and `-C` aren't compatible, this effectively runs `ls -C` in `clap` if you choose...`clap` also supports hard conflicts that fail parsing). (Thanks to [Vinatorul](https://github.com/Vinatorul)!)
+* Supports the Unix `--` meaning, only positional arguments follow
+
+## Quick Example
+
+The following examples show a quick example of some of the very basic functionality of `clap`. For more advanced usage, such as requirements, conflicts, groups, multiple values and occurrences see the [documentation](https://docs.rs/clap/), [examples/](examples) directory of this repository or the [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U).
+
+ **NOTE:** All of these examples are functionally the same, but show different styles in which to use `clap`. These different styles are purely a matter of personal preference.
+
+The first example shows a method using the 'Builder Pattern' which allows more advanced configuration options (not shown in this small example), or even dynamically generating arguments when desired.
+
+```rust
+// (Full example with detailed comments in examples/01b_quick_example.rs)
+//
+// This example demonstrates clap's full 'builder pattern' style of creating arguments which is
+// more verbose, but allows easier editing, and at times more advanced options, or the possibility
+// to generate arguments dynamically.
+extern crate clap;
+use clap::{Arg, App, SubCommand};
+
+fn main() {
+ let matches = App::new("My Super Program")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .arg(Arg::with_name("config")
+ .short("c")
+ .long("config")
+ .value_name("FILE")
+ .help("Sets a custom config file")
+ .takes_value(true))
+ .arg(Arg::with_name("INPUT")
+ .help("Sets the input file to use")
+ .required(true)
+ .index(1))
+ .arg(Arg::with_name("v")
+ .short("v")
+ .multiple(true)
+ .help("Sets the level of verbosity"))
+ .subcommand(SubCommand::with_name("test")
+ .about("controls testing features")
+ .version("1.3")
+ .author("Someone E. <someone_else@other.com>")
+ .arg(Arg::with_name("debug")
+ .short("d")
+ .help("print debug information verbosely")))
+ .get_matches();
+
+ // Gets a value for config if supplied by user, or defaults to "default.conf"
+ let config = matches.value_of("config").unwrap_or("default.conf");
+ println!("Value for config: {}", config);
+
+ // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
+ // required we could have used an 'if let' to conditionally get the value)
+ println!("Using input file: {}", matches.value_of("INPUT").unwrap());
+
+ // Vary the output based on how many times the user used the "verbose" flag
+ // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
+ match matches.occurrences_of("v") {
+ 0 => println!("No verbose info"),
+ 1 => println!("Some verbose info"),
+ 2 => println!("Tons of verbose info"),
+ 3 | _ => println!("Don't be crazy"),
+ }
+
+ // You can handle information about subcommands by requesting their matches by name
+ // (as below), requesting just the name used, or both at the same time
+ if let Some(matches) = matches.subcommand_matches("test") {
+ if matches.is_present("debug") {
+ println!("Printing debug info...");
+ } else {
+ println!("Printing normally...");
+ }
+ }
+
+ // more program logic goes here...
+}
+```
+
+One could also optionally declare their CLI in YAML format and keep your Rust source tidy
+or support multiple localized translations by having different YAML files for each localization.
+
+First, create the `cli.yml` file to hold your CLI options, but it could be called anything we like:
+
+```yaml
+name: myapp
+version: "1.0"
+author: Kevin K. <kbknapp@gmail.com>
+about: Does awesome things
+args:
+ - config:
+ short: c
+ long: config
+ value_name: FILE
+ help: Sets a custom config file
+ takes_value: true
+ - INPUT:
+ help: Sets the input file to use
+ required: true
+ index: 1
+ - verbose:
+ short: v
+ multiple: true
+ help: Sets the level of verbosity
+subcommands:
+ - test:
+ about: controls testing features
+ version: "1.3"
+ author: Someone E. <someone_else@other.com>
+ args:
+ - debug:
+ short: d
+ help: print debug information
+```
+
+Since this feature requires additional dependencies that not everyone may want, it is *not* compiled in by default and we need to enable a feature flag in Cargo.toml:
+
+Simply change your `clap = "2.33"` to `clap = {version = "2.33", features = ["yaml"]}`.
+
+Finally we create our `main.rs` file just like we would have with the previous two examples:
+
+```rust
+// (Full example with detailed comments in examples/17_yaml.rs)
+//
+// This example demonstrates clap's building from YAML style of creating arguments which is far
+// more clean, but takes a very small performance hit compared to the other two methods.
+#[macro_use]
+extern crate clap;
+use clap::App;
+
+fn main() {
+ // The YAML file is found relative to the current file, similar to how modules are found
+ let yaml = load_yaml!("cli.yml");
+ let matches = App::from_yaml(yaml).get_matches();
+
+ // Same as previous examples...
+}
+```
+
+If you were to compile any of the above programs and run them with the flag `--help` or `-h` (or `help` subcommand, since we defined `test` as a subcommand) the following would be output
+
+```sh
+$ myprog --help
+My Super Program 1.0
+Kevin K. <kbknapp@gmail.com>
+Does awesome things
+
+USAGE:
+ MyApp [FLAGS] [OPTIONS] <INPUT> [SUBCOMMAND]
+
+FLAGS:
+ -h, --help Prints help information
+ -v Sets the level of verbosity
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --config <FILE> Sets a custom config file
+
+ARGS:
+ INPUT The input file to use
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test Controls testing features
+```
+
+**NOTE:** You could also run `myapp test --help` or `myapp help test` to see the help message for the `test` subcommand.
+
+There are also two other methods to create CLIs. Which style you choose is largely a matter of personal preference. The two other methods are:
+
+* Using [usage strings (examples/01a_quick_example.rs)](examples/01a_quick_example.rs) similar to (but not exact) docopt style usage statements. This is far less verbose than the above methods, but incurs a slight runtime penalty.
+* Using [a macro (examples/01c_quick_example.rs)](examples/01c_quick_example.rs) which is like a hybrid of the builder and usage string style. It's less verbose, but doesn't incur the runtime penalty of the usage string style. The downside is that it's harder to debug, and more opaque.
+
+Examples of each method can be found in the [examples/](examples) directory of this repository.
+
+## Try it!
+
+### Pre-Built Test
+
+To try out the pre-built examples, use the following steps:
+
+* Clone the repository `$ git clone https://github.com/clap-rs/clap && cd clap-rs/`
+* Compile the example `$ cargo build --example <EXAMPLE>`
+* Run the help info `$ ./target/debug/examples/<EXAMPLE> --help`
+* Play with the arguments!
+* You can also do a onetime run via `$ cargo run --example <EXAMPLE> -- [args to example]`
+
+### BYOB (Build Your Own Binary)
+
+To test out `clap`'s default auto-generated help/version follow these steps:
+* Create a new cargo project `$ cargo new fake --bin && cd fake`
+* Add `clap` to your `Cargo.toml`
+
+```toml
+[dependencies]
+clap = "2"
+```
+
+* Add the following to your `src/main.rs`
+
+```rust
+extern crate clap;
+use clap::App;
+
+fn main() {
+ App::new("fake").version("v1.0-beta").get_matches();
+}
+```
+
+* Build your program `$ cargo build --release`
+* Run with help or version `$ ./target/release/fake --help` or `$ ./target/release/fake --version`
+
+## Usage
+
+For full usage, add `clap` as a dependency in your `Cargo.toml` () to use from crates.io:
+
+```toml
+[dependencies]
+clap = "~2.33"
+```
+
+(**note**: If you are concerned with supporting a minimum version of Rust that is *older* than the current stable Rust minus 2 stable releases, it's recommended to use the `~major.minor.patch` style versions in your `Cargo.toml` which will only update the patch version automatically. For more information see the [Compatibility Policy](#compatibility-policy))
+
+Then add `extern crate clap;` to your crate root.
+
+Define a list of valid arguments for your program (see the [documentation](https://docs.rs/clap/) or [examples/](examples) directory of this repo)
+
+Then run `cargo build` or `cargo update && cargo build` for your project.
+
+### Optional Dependencies / Features
+
+#### Features enabled by default
+
+* **"suggestions"**: Turns on the `Did you mean '--myoption'?` feature for when users make typos. (builds dependency `strsim`)
+* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` only on non-Windows targets)
+* **"vec_map"**: Use [`VecMap`](https://crates.io/crates/vec_map) internally instead of a [`BTreeMap`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html). This feature provides a _slight_ performance improvement. (builds dependency `vec_map`)
+
+To disable these, add this to your `Cargo.toml`:
+
+```toml
+[dependencies.clap]
+version = "2.33"
+default-features = false
+```
+
+You can also selectively enable only the features you'd like to include, by adding:
+
+```toml
+[dependencies.clap]
+version = "2.33"
+default-features = false
+
+# Cherry-pick the features you'd like to use
+features = [ "suggestions", "color" ]
+```
+
+#### Opt-in features
+
+* **"yaml"**: Enables building CLIs from YAML documents. (builds dependency `yaml-rust`)
+* **"unstable"**: Enables unstable `clap` features that may change from release to release
+* **"wrap_help"**: Turns on the help text wrapping feature, based on the terminal size. (builds dependency `term-size`)
+
+### Dependencies Tree
+
+The following graphic depicts `clap`s dependency graph (generated using [cargo-graph](https://github.com/kbknapp/cargo-graph)).
+
+ * **Dashed** Line: Optional dependency
+ * **Red** Color: **NOT** included by default (must use cargo `features` to enable)
+ * **Blue** Color: Dev dependency, only used while developing.
+
+![clap dependencies](clap_dep_graph.png)
+
+### More Information
+
+You can find complete documentation on the [docs.rs](https://docs.rs/clap/) for this project.
+
+You can also find usage examples in the [examples/](examples) directory of this repo.
+
+#### Video Tutorials
+
+There's also the video tutorial series [Argument Parsing with Rust v2](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U).
+
+These videos slowly trickle out as I finish them and currently a work in progress.
+
+## How to Contribute
+
+Details on how to contribute can be found in the [CONTRIBUTING.md](.github/CONTRIBUTING.md) file.
+
+### Compatibility Policy
+
+Because `clap` takes SemVer and compatibility seriously, this is the official policy regarding breaking changes and minimum required versions of Rust.
+
+`clap` will pin the minimum required version of Rust to the CI builds. Bumping the minimum version of Rust is considered a minor breaking change, meaning *at a minimum* the minor version of `clap` will be bumped.
+
+In order to keep from being surprised of breaking changes, it is **highly** recommended to use the `~major.minor.patch` style in your `Cargo.toml` only if you wish to target a version of Rust that is *older* than current stable minus two releases:
+
+```toml
+[dependencies]
+clap = "~2.33"
+```
+
+This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore cannot break due to new features, or bumped minimum versions of Rust.
+
+#### Warning about '~' Dependencies
+
+Using `~` can cause issues in certain circumstances.
+
+From @alexcrichton:
+
+Right now Cargo's version resolution is pretty naive, it's just a brute-force search of the solution space, returning the first resolvable graph. This also means that it currently won't terminate until it proves there is not possible resolvable graph. This leads to situations where workspaces with multiple binaries, for example, have two different dependencies such as:
+
+```toml,no_sync
+
+# In one Cargo.toml
+[dependencies]
+clap = "~2.33.0"
+
+# In another Cargo.toml
+[dependencies]
+clap = "2.33.0"
+```
+
+This is inherently an unresolvable crate graph in Cargo right now. Cargo requires there's only one major version of a crate, and being in the same workspace these two crates must share a version. This is impossible in this location, though, as these version constraints cannot be met.
+
+#### Minimum Version of Rust
+
+`clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.32.0, meaning `clap` is guaranteed to compile with 1.30.0 and beyond.
+
+At the 1.33.0 stable release, `clap` will be guaranteed to compile with 1.31.0 and beyond, etc.
+
+Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be clearly annotated in the `CHANGELOG.md`
+
+#### Breaking Changes
+
+`clap` takes a similar policy to Rust and will bump the major version number upon breaking changes with only the following exceptions:
+
+ * The breaking change is to fix a security concern
+ * The breaking change is to be fixing a bug (i.e. relying on a bug as a feature)
+ * The breaking change is a feature isn't used in the wild, or all users of said feature have given approval *prior* to the change
+
+#### Compatibility with Wasm
+
+A best effort is made to ensure that `clap` will work on projects targeting `wasm32-unknown-unknown`. However there is no dedicated CI build
+covering this specific target.
+
+## License
+
+`clap` is licensed under the MIT license. Please read the [LICENSE-MIT](LICENSE-MIT) file in this repository for more information.
+
+## Related Crates
+
+There are several excellent crates which can be used with `clap`, I recommend checking them all out! If you've got a crate that would be a good fit to be used with `clap` open an issue and let me know, I'd love to add it!
+
+* [`structopt`](https://github.com/TeXitoi/structopt) - This crate allows you to define a struct, and build a CLI from it! No more "stringly typed" and it uses `clap` behind the scenes! (*Note*: There is work underway to pull this crate into mainline `clap`).
+* [`assert_cli`](https://github.com/assert-rs/assert_cli) - This crate allows you test your CLIs in a very intuitive and functional way!
+
+## Recent Breaking Changes
+
+`clap` follows semantic versioning, so breaking changes should only happen upon major version bumps. The only exception to this rule is breaking changes that happen due to implementation that was deemed to be a bug, security concerns, or it can be reasonably proved to affect no code. For the full details, see [CHANGELOG.md](./CHANGELOG.md).
+
+As of 2.27.0:
+
+* Argument values now take precedence over subcommand names. This only arises by using unrestrained multiple values and subcommands together where the subcommand name can coincide with one of the multiple values. Such as `$ prog <files>... <subcommand>`. The fix is to place restraints on number of values, or disallow the use of `$ prog <prog-args> <subcommand>` structure.
+
+As of 2.0.0 (From 1.x)
+
+* **Fewer lifetimes! Yay!**
+ * `App<'a, 'b, 'c, 'd, 'e, 'f>` => `App<'a, 'b>`
+ * `Arg<'a, 'b, 'c, 'd, 'e, 'f>` => `Arg<'a, 'b>`
+ * `ArgMatches<'a, 'b>` => `ArgMatches<'a>`
+* **Simply Renamed**
+ * `App::arg_group` => `App::group`
+ * `App::arg_groups` => `App::groups`
+ * `ArgGroup::add` => `ArgGroup::arg`
+ * `ArgGroup::add_all` => `ArgGroup::args`
+ * `ClapError` => `Error`
+ * struct field `ClapError::error_type` => `Error::kind`
+ * `ClapResult` => `Result`
+ * `ClapErrorType` => `ErrorKind`
+* **Removed Deprecated Functions and Methods**
+ * `App::subcommands_negate_reqs`
+ * `App::subcommand_required`
+ * `App::arg_required_else_help`
+ * `App::global_version(bool)`
+ * `App::versionless_subcommands`
+ * `App::unified_help_messages`
+ * `App::wait_on_error`
+ * `App::subcommand_required_else_help`
+ * `SubCommand::new`
+ * `App::error_on_no_subcommand`
+ * `Arg::new`
+ * `Arg::mutually_excludes`
+ * `Arg::mutually_excludes_all`
+ * `Arg::mutually_overrides_with`
+ * `simple_enum!`
+* **Renamed Error Variants**
+ * `InvalidUnicode` => `InvalidUtf8`
+ * `InvalidArgument` => `UnknownArgument`
+* **Usage Parser**
+ * Value names can now be specified inline, i.e. `-o, --option <FILE> <FILE2> 'some option which takes two files'`
+ * **There is now a priority of order to determine the name** - This is perhaps the biggest breaking change. See the documentation for full details. Prior to this change, the value name took precedence. **Ensure your args are using the proper names (i.e. typically the long or short and NOT the value name) throughout the code**
+* `ArgMatches::values_of` returns an `Values` now which implements `Iterator` (should not break any code)
+* `crate_version!` returns `&'static str` instead of `String`
+
+### Deprecations
+
+Old method names will be left around for several minor version bumps, or one major version bump.
+
+As of 2.27.0:
+
+* **AppSettings::PropagateGlobalValuesDown:** this setting deprecated and is no longer required to propagate values down or up
diff --git a/clap/SPONSORS.md b/clap/SPONSORS.md
new file mode 100644
index 0000000..67f5544
--- /dev/null
+++ b/clap/SPONSORS.md
@@ -0,0 +1,17 @@
+Below is a list of sponsors for the clap-rs project
+
+If you are interested in becoming a sponsor for this project please our [sponsorship page](https://clap.rs/sponsorship/).
+
+## Recurring Sponsors:
+
+| [<img alt="Noelia Seva-Gonzalez" src="https://clap.rs/wp-content/uploads/2017/10/noelia_sm-1.png" width="117">](https://noeliasg.com/about/) | [<img alt="messense" src="https://clap.rs/wp-content/uploads/2018/01/messense-400x400.png" width="117">](https://github.com/messense) | [<img alt="Josh" src="https://clap.rs/wp-content/uploads/2018/11/josh_t.jpg" width="117">](https://joshtriplett.org) | <img alt="Stephen Oats" src="https://clap.rs/wp-content/uploads/2019/03/stephenoats.png" width="117"> |
+|:-:|:-:|:-:|:-:|
+|Noelia Seva-Gonzalez | Messense | Josh Triplett | Stephen Oats |
+
+
+## Single-Donation and Former Sponsors:
+
+| [<img alt="Rob Tsuk" src="https://clap.rs/wp-content/uploads/2017/10/robtsuk_sm.png" width="117">](https://github.com/rtsuk)| | |
+|:-:|:-:|:-:|
+|Rob Tsuk| | |
+
diff --git a/clap/benches/01_default.rs b/clap/benches/01_default.rs
new file mode 100644
index 0000000..24e619e
--- /dev/null
+++ b/clap/benches/01_default.rs
@@ -0,0 +1,18 @@
+#![feature(test)]
+
+extern crate clap;
+extern crate test;
+
+use clap::App;
+
+use test::Bencher;
+
+#[bench]
+fn build_app(b: &mut Bencher) {
+ b.iter(|| App::new("claptests"));
+}
+
+#[bench]
+fn parse_clean(b: &mut Bencher) {
+ b.iter(|| App::new("claptests").get_matches_from(vec![""]));
+}
diff --git a/clap/benches/02_simple.rs b/clap/benches/02_simple.rs
new file mode 100644
index 0000000..010fa86
--- /dev/null
+++ b/clap/benches/02_simple.rs
@@ -0,0 +1,114 @@
+#![feature(test)]
+
+extern crate clap;
+extern crate test;
+
+use clap::{App, Arg};
+
+use test::Bencher;
+
+macro_rules! create_app {
+ () => ({
+ App::new("claptests")
+ .version("0.1")
+ .about("tests clap library")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .args_from_usage("-f --flag 'tests flags'
+ -o --option=[opt] 'tests options'
+ [positional] 'tests positional'")
+ })
+}
+
+#[bench]
+fn build_app(b: &mut Bencher) {
+
+ b.iter(|| create_app!());
+}
+
+#[bench]
+fn add_flag(b: &mut Bencher) {
+ fn build_app() -> App<'static, 'static> {
+ App::new("claptests")
+ }
+
+ b.iter(|| build_app().arg(Arg::from_usage("-s, --some 'something'")));
+}
+
+#[bench]
+fn add_flag_ref(b: &mut Bencher) {
+ fn build_app() -> App<'static, 'static> {
+ App::new("claptests")
+ }
+
+ b.iter(|| {
+ let arg = Arg::from_usage("-s, --some 'something'");
+ build_app().arg(&arg)
+ });
+}
+
+#[bench]
+fn add_opt(b: &mut Bencher) {
+ fn build_app() -> App<'static, 'static> {
+ App::new("claptests")
+ }
+
+ b.iter(|| build_app().arg(Arg::from_usage("-s, --some <FILE> 'something'")));
+}
+
+#[bench]
+fn add_opt_ref(b: &mut Bencher) {
+ fn build_app() -> App<'static, 'static> {
+ App::new("claptests")
+ }
+
+ b.iter(|| {
+ let arg = Arg::from_usage("-s, --some <FILE> 'something'");
+ build_app().arg(&arg)
+ });
+}
+
+#[bench]
+fn add_pos(b: &mut Bencher) {
+ fn build_app() -> App<'static, 'static> {
+ App::new("claptests")
+ }
+
+ b.iter(|| build_app().arg(Arg::with_name("some")));
+}
+
+#[bench]
+fn add_pos_ref(b: &mut Bencher) {
+ fn build_app() -> App<'static, 'static> {
+ App::new("claptests")
+ }
+
+ b.iter(|| {
+ let arg = Arg::with_name("some");
+ build_app().arg(&arg)
+ });
+}
+
+#[bench]
+fn parse_clean(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec![""]));
+}
+
+#[bench]
+fn parse_flag(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"]));
+}
+
+#[bench]
+fn parse_option(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1"]));
+}
+
+#[bench]
+fn parse_positional(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "arg1"]));
+}
+
+#[bench]
+fn parse_complex(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1", "-f", "arg1"]));
+}
diff --git a/clap/benches/03_complex.rs b/clap/benches/03_complex.rs
new file mode 100644
index 0000000..b00fc4e
--- /dev/null
+++ b/clap/benches/03_complex.rs
@@ -0,0 +1,230 @@
+#![feature(test)]
+
+#[macro_use]
+extern crate clap;
+extern crate test;
+
+use clap::{App, Arg, SubCommand, AppSettings};
+
+use test::Bencher;
+
+static ARGS: &'static str = "-o --option=[opt]... 'tests options'
+ [positional] 'tests positionals'";
+static OPT3_VALS: [&'static str; 2] = ["fast", "slow"];
+static POS3_VALS: [&'static str; 2] = ["vi", "emacs"];
+
+macro_rules! create_app {
+ () => ({
+ App::new("claptests")
+ .version("0.1")
+ .about("tests clap library")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .args_from_usage(ARGS)
+ .arg(Arg::from_usage("-f --flag... 'tests flags'")
+ .global(true))
+ .args(&[
+ Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("option2"),
+ Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"),
+ Arg::from_usage("[positional2] 'tests positionals with exclusions'"),
+ Arg::from_usage("-O --Option [option3] 'tests options with specific value sets'").possible_values(&OPT3_VALS),
+ Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(&POS3_VALS),
+ Arg::from_usage("--multvals [one] [two] 'Tests multiple values, not mult occs'"),
+ Arg::from_usage("--multvalsmo... [one] [two] 'Tests multiple values, not mult occs'"),
+ Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2),
+ Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3)
+ ])
+ .subcommand(SubCommand::with_name("subcmd")
+ .about("tests subcommands")
+ .version("0.1")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .arg_from_usage("-o --option [scoption]... 'tests options'")
+ .arg_from_usage("[scpositional] 'tests positionals'"))
+ })
+}
+
+#[bench]
+fn create_app_from_usage(b: &mut Bencher) {
+
+ b.iter(|| create_app!());
+}
+
+#[bench]
+fn create_app_builder(b: &mut Bencher) {
+ b.iter(|| {
+ App::new("claptests")
+ .version("0.1")
+ .about("tests clap library")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .arg(Arg::with_name("opt")
+ .help("tests options")
+ .short("o")
+ .long("option")
+ .takes_value(true)
+ .multiple(true))
+ .arg(Arg::with_name("positional")
+ .help("tests positionals")
+ .index(1))
+ .arg(Arg::with_name("flag")
+ .short("f")
+ .help("tests flags")
+ .long("flag")
+ .multiple(true)
+ .global(true))
+ .arg(Arg::with_name("flag2")
+ .short("F")
+ .help("tests flags with exclusions")
+ .conflicts_with("flag")
+ .requires("option2"))
+ .arg(Arg::with_name("option2")
+ .help("tests long options with exclusions")
+ .conflicts_with("option")
+ .requires("positional2")
+ .takes_value(true)
+ .long("long-option-2"))
+ .arg(Arg::with_name("positional2")
+ .index(3)
+ .help("tests positionals with exclusions"))
+ .arg(Arg::with_name("option3")
+ .short("O")
+ .long("Option")
+ .takes_value(true)
+ .help("tests options with specific value sets")
+ .possible_values(&OPT3_VALS))
+ .arg(Arg::with_name("positional3")
+ .multiple(true)
+ .help("tests positionals with specific values")
+ .index(4)
+ .possible_values(&POS3_VALS))
+ .arg(Arg::with_name("multvals")
+ .long("multvals")
+ .takes_value(true)
+ .help("Tests multiple values, not mult occs")
+ .value_names(&["one", "two"]))
+ .arg(Arg::with_name("multvalsmo")
+ .long("multvalsmo")
+ .takes_value(true)
+ .multiple(true)
+ .help("Tests multiple values, not mult occs")
+ .value_names(&["one", "two"]))
+ .arg(Arg::with_name("minvals")
+ .long("minvals2")
+ .multiple(true)
+ .takes_value(true)
+ .help("Tests 2 min vals")
+ .min_values(2))
+ .arg(Arg::with_name("maxvals")
+ .long("maxvals3")
+ .takes_value(true)
+ .multiple(true)
+ .help("Tests 3 max vals")
+ .max_values(3))
+ .subcommand(SubCommand::with_name("subcmd")
+ .about("tests subcommands")
+ .version("0.1")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .arg(Arg::with_name("scoption")
+ .short("o")
+ .long("option")
+ .multiple(true)
+ .takes_value(true)
+ .help("tests options"))
+ .arg(Arg::with_name("scpositional")
+ .index(1)
+ .help("tests positionals")));
+ });
+}
+
+#[bench]
+fn create_app_macros(b: &mut Bencher) {
+ b.iter(|| {
+ clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg opt: -o --option +takes_value ... "tests options")
+ (@arg positional: index(1) "tests positionals")
+ (@arg flag: -f --flag ... +global "tests flags")
+ (@arg flag2: -F conflicts_with[flag] requires[option2]
+ "tests flags with exclusions")
+ (@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
+ "tests long options with exclusions")
+ (@arg positional2: index(2) "tests positionals with exclusions")
+ (@arg option3: -O --Option +takes_value possible_value[fast slow]
+ "tests options with specific value sets")
+ (@arg positional3: index(3) ... possible_value[vi emacs]
+ "tests positionals with specific values")
+ (@arg multvals: --multvals +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
+ (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
+ (@subcommand subcmd =>
+ (about: "tests subcommands")
+ (version: "0.1")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg scoption: -o --option ... +takes_value "tests options")
+ (@arg scpositional: index(1) "tests positionals"))
+ );
+ });
+}
+
+#[bench]
+fn parse_clean(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec![""]));
+}
+
+#[bench]
+fn parse_flag(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"]));
+}
+
+#[bench]
+fn parse_option(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1"]));
+}
+
+#[bench]
+fn parse_positional(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "arg1"]));
+}
+
+#[bench]
+fn parse_sc_clean(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd"]));
+}
+
+#[bench]
+fn parse_sc_flag(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-f"]));
+}
+
+#[bench]
+fn parse_sc_option(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-o", "option1"]));
+}
+
+#[bench]
+fn parse_sc_positional(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "arg1"]));
+}
+
+#[bench]
+fn parse_complex1(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "-ff", "-o", "option1", "arg1", "-O", "fast", "arg2", "--multvals", "one", "two", "emacs"]));
+}
+
+#[bench]
+fn parse_complex2(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "arg1", "-f", "arg2", "--long-option-2", "some", "-O", "slow", "--multvalsmo", "one", "two", "--minvals2", "3", "2", "1"]));
+}
+
+#[bench]
+fn parse_complex2_with_args_negate_scs(b: &mut Bencher) {
+ b.iter(|| create_app!().setting(AppSettings::ArgsNegateSubcommands).get_matches_from(vec!["myprog", "arg1", "-f", "arg2", "--long-option-2", "some", "-O", "slow", "--multvalsmo", "one", "two", "--minvals2", "3", "2", "1"]));
+}
+
+#[bench]
+fn parse_sc_complex(b: &mut Bencher) {
+ b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-f", "-o", "option1", "arg1"]));
+}
diff --git a/clap/benches/04_new_help.rs b/clap/benches/04_new_help.rs
new file mode 100644
index 0000000..f033efb
--- /dev/null
+++ b/clap/benches/04_new_help.rs
@@ -0,0 +1,198 @@
+#![feature(test)]
+
+extern crate clap;
+extern crate test;
+
+use test::Bencher;
+
+use std::io::Cursor;
+
+use clap::App;
+use clap::{Arg, SubCommand};
+
+fn build_help(app: &App) -> String {
+ let mut buf = Cursor::new(Vec::with_capacity(50));
+ app.write_help(&mut buf).unwrap();
+ let content = buf.into_inner();
+ String::from_utf8(content).unwrap()
+}
+
+fn app_example1<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .args_from_usage("-c, --config=[FILE] 'Sets a custom config file'
+ <output> 'Sets an optional output file'
+ -d... 'Turn debugging information on'")
+ .subcommand(SubCommand::with_name("test")
+ .about("does testing things")
+ .arg_from_usage("-l, --list 'lists test values'"))
+}
+
+fn app_example2<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+}
+
+fn app_example3<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp")
+ .arg(Arg::with_name("debug")
+ .help("turn on debugging information")
+ .short("d"))
+ .args(&[Arg::with_name("config")
+ .help("sets the config file to use")
+ .takes_value(true)
+ .short("c")
+ .long("config"),
+ Arg::with_name("input")
+ .help("the input file to use")
+ .index(1)
+ .required(true)])
+ .arg_from_usage("--license 'display the license file'")
+ .args_from_usage("[output] 'Supply an output file to use'
+ -i, --int=[IFACE] 'Set an interface to use'")
+}
+
+fn app_example4<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp")
+ .about("Parses an input file to do awesome things")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .arg(Arg::with_name("debug")
+ .help("turn on debugging information")
+ .short("d")
+ .long("debug"))
+ .arg(Arg::with_name("config")
+ .help("sets the config file to use")
+ .short("c")
+ .long("config"))
+ .arg(Arg::with_name("input")
+ .help("the input file to use")
+ .index(1)
+ .required(true))
+}
+
+fn app_example5<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp").arg(Arg::with_name("awesome")
+ .help("turns up the awesome")
+ .short("a")
+ .long("awesome")
+ .multiple(true)
+ .requires("config")
+ .conflicts_with("output"))
+}
+
+fn app_example6<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp")
+ .arg(Arg::with_name("input")
+ .help("the input file to use")
+ .index(1)
+ .requires("config")
+ .conflicts_with("output")
+ .required(true))
+ .arg(Arg::with_name("config")
+ .help("the config file to use")
+ .index(2))
+}
+
+fn app_example7<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp")
+ .arg(Arg::with_name("config"))
+ .arg(Arg::with_name("output"))
+ .arg(Arg::with_name("input")
+ .help("the input file to use")
+ .takes_value(true)
+ .short("i")
+ .long("input")
+ .multiple(true)
+ .required(true)
+ .requires("config")
+ .conflicts_with("output"))
+}
+
+fn app_example8<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp")
+ .arg(Arg::with_name("config"))
+ .arg(Arg::with_name("output"))
+ .arg(Arg::with_name("input")
+ .help("the input file to use")
+ .takes_value(true)
+ .short("i")
+ .long("input")
+ .multiple(true)
+ .required(true)
+ .requires("config")
+ .conflicts_with("output"))
+}
+
+fn app_example10<'b, 'c>() -> App<'b, 'c> {
+ App::new("myapp")
+ .about("does awesome things")
+ .arg(Arg::with_name("CONFIG")
+ .help("The config file to use (default is \"config.json\")")
+ .short("c")
+ .takes_value(true))
+}
+
+#[bench]
+fn example1(b: &mut Bencher) {
+ let app = app_example1();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example2(b: &mut Bencher) {
+ let app = app_example2();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example3(b: &mut Bencher) {
+ let app = app_example3();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example4(b: &mut Bencher) {
+ let app = app_example4();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example5(b: &mut Bencher) {
+ let app = app_example5();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example6(b: &mut Bencher) {
+ let app = app_example6();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example7(b: &mut Bencher) {
+ let app = app_example7();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example8(b: &mut Bencher) {
+ let app = app_example8();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example10(b: &mut Bencher) {
+ let app = app_example10();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn example4_template(b: &mut Bencher) {
+ let app = app_example4().template("{bin} {version}\n{author}\n{about}\n\nUSAGE:\n {usage}\n\nFLAGS:\n{flags}\n\nARGS:\n{args}\n");
+ b.iter(|| build_help(&app));
+}
diff --git a/clap/benches/05_ripgrep.rs b/clap/benches/05_ripgrep.rs
new file mode 100644
index 0000000..7db1552
--- /dev/null
+++ b/clap/benches/05_ripgrep.rs
@@ -0,0 +1,777 @@
+// Used to simulate a fairly large number of options/flags and parsing with thousands of positional
+// args
+//
+// CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a
+
+#![feature(test)]
+
+extern crate clap;
+extern crate test;
+#[macro_use]
+extern crate lazy_static;
+
+use clap::{App, AppSettings, Arg, ArgSettings};
+
+use test::Bencher;
+use std::collections::HashMap;
+use std::io::Cursor;
+
+#[bench]
+fn build_app_short(b: &mut Bencher) { b.iter(|| app_short()); }
+
+#[bench]
+fn build_app_long(b: &mut Bencher) { b.iter(|| app_long()); }
+
+#[bench]
+fn build_help_short(b: &mut Bencher) {
+ let app = app_short();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn build_help_long(b: &mut Bencher) {
+ let app = app_long();
+ b.iter(|| build_help(&app));
+}
+
+#[bench]
+fn parse_clean(b: &mut Bencher) { b.iter(|| app_short().get_matches_from(vec!["rg", "pat"])); }
+
+#[bench]
+fn parse_complex(b: &mut Bencher) {
+ b.iter(|| {
+ app_short().get_matches_from(vec!["rg",
+ "pat",
+ "-cFlN",
+ "-pqr=some",
+ "--null",
+ "--no-filename",
+ "--no-messages",
+ "-SH",
+ "-C5",
+ "--follow",
+ "-e some"])
+ });
+}
+
+#[bench]
+fn parse_lots(b: &mut Bencher) {
+ b.iter(|| {
+ app_short()
+ .get_matches_from(vec!["rg", "pat", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some"])
+ });
+}
+
+const ABOUT: &'static str = "
+ripgrep (rg) recursively searches your current directory for a regex pattern.
+
+ripgrep's regex engine uses finite automata and guarantees linear time
+searching. Because of this, features like backreferences and arbitrary
+lookaround are not supported.
+
+Project home page: https://github.com/BurntSushi/ripgrep
+
+Use -h for short descriptions and --help for more details.";
+
+const USAGE: &'static str = "
+ rg [OPTIONS] <pattern> [<path> ...]
+ rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
+ rg [OPTIONS] --files [<path> ...]
+ rg [OPTIONS] --type-list";
+
+const TEMPLATE: &'static str = "\
+{bin} {version}
+{author}
+{about}
+
+USAGE:{usage}
+
+ARGS:
+{positionals}
+
+OPTIONS:
+{unified}";
+
+/// Build a clap application with short help strings.
+pub fn app_short() -> App<'static, 'static> { app(false, |k| USAGES[k].short) }
+
+/// Build a clap application with long help strings.
+pub fn app_long() -> App<'static, 'static> { app(true, |k| USAGES[k].long) }
+
+
+/// Build the help text of an application.
+fn build_help(app: &App) -> String {
+ let mut buf = Cursor::new(Vec::with_capacity(50));
+ app.write_help(&mut buf).unwrap();
+ let content = buf.into_inner();
+ String::from_utf8(content).unwrap()
+}
+
+
+/// Build a clap application parameterized by usage strings.
+///
+/// The function given should take a clap argument name and return a help
+/// string. `app` will panic if a usage string is not defined.
+///
+/// This is an intentionally stand-alone module so that it can be used easily
+/// in a `build.rs` script to build shell completion files.
+fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
+ where F: Fn(&'static str) -> &'static str
+{
+ let arg = |name| Arg::with_name(name).help(doc(name)).next_line_help(next_line_help);
+ let flag = |name| arg(name).long(name);
+
+ App::new("ripgrep")
+ .author("BurntSushi") // simulating since it's only a bench
+ .version("0.4.0") // Simulating
+ .about(ABOUT)
+ .max_term_width(100)
+ .setting(AppSettings::UnifiedHelpMessage)
+ .usage(USAGE)
+ .template(TEMPLATE)
+ // Handle help/version manually to make their output formatting
+ // consistent with short/long views.
+ .arg(arg("help-short").short("h"))
+ .arg(flag("help"))
+ .arg(flag("version").short("V"))
+ // First, set up primary positional/flag arguments.
+ .arg(arg("pattern")
+ .required_unless_one(&[
+ "file", "files", "help-short", "help", "regexp", "type-list",
+ "version",
+ ]))
+ .arg(arg("path").multiple(true))
+ .arg(flag("regexp").short("e")
+ .takes_value(true).multiple(true).number_of_values(1)
+ .set(ArgSettings::AllowLeadingHyphen)
+ .value_name("pattern"))
+ .arg(flag("files")
+ // This should also conflict with `pattern`, but the first file
+ // path will actually be in `pattern`.
+ .conflicts_with_all(&["file", "regexp", "type-list"]))
+ .arg(flag("type-list")
+ .conflicts_with_all(&["file", "files", "pattern", "regexp"]))
+ // Second, set up common flags.
+ .arg(flag("text").short("a"))
+ .arg(flag("count").short("c"))
+ .arg(flag("color")
+ .value_name("WHEN")
+ .takes_value(true)
+ .hide_possible_values(true)
+ .possible_values(&["never", "auto", "always", "ansi"]))
+ .arg(flag("colors").value_name("SPEC")
+ .takes_value(true).multiple(true).number_of_values(1))
+ .arg(flag("fixed-strings").short("F"))
+ .arg(flag("glob").short("g")
+ .takes_value(true).multiple(true).number_of_values(1)
+ .value_name("GLOB"))
+ .arg(flag("ignore-case").short("i"))
+ .arg(flag("line-number").short("n"))
+ .arg(flag("no-line-number").short("N"))
+ .arg(flag("quiet").short("q"))
+ .arg(flag("type").short("t")
+ .takes_value(true).multiple(true).number_of_values(1)
+ .value_name("TYPE"))
+ .arg(flag("type-not").short("T")
+ .takes_value(true).multiple(true).number_of_values(1)
+ .value_name("TYPE"))
+ .arg(flag("unrestricted").short("u")
+ .multiple(true))
+ .arg(flag("invert-match").short("v"))
+ .arg(flag("word-regexp").short("w"))
+ // Third, set up less common flags.
+ .arg(flag("after-context").short("A")
+ .value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("before-context").short("B")
+ .value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("context").short("C")
+ .value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("column"))
+ .arg(flag("context-separator")
+ .value_name("SEPARATOR").takes_value(true))
+ .arg(flag("debug"))
+ .arg(flag("file").short("f")
+ .value_name("FILE").takes_value(true)
+ .multiple(true).number_of_values(1))
+ .arg(flag("files-with-matches").short("l"))
+ .arg(flag("files-without-match"))
+ .arg(flag("with-filename").short("H"))
+ .arg(flag("no-filename"))
+ .arg(flag("heading").overrides_with("no-heading"))
+ .arg(flag("no-heading").overrides_with("heading"))
+ .arg(flag("hidden"))
+ .arg(flag("ignore-file")
+ .value_name("FILE").takes_value(true)
+ .multiple(true).number_of_values(1))
+ .arg(flag("follow").short("L"))
+ .arg(flag("max-count")
+ .short("m").value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("maxdepth")
+ .value_name("NUM").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("mmap"))
+ .arg(flag("no-messages"))
+ .arg(flag("no-mmap"))
+ .arg(flag("no-ignore"))
+ .arg(flag("no-ignore-parent"))
+ .arg(flag("no-ignore-vcs"))
+ .arg(flag("null"))
+ .arg(flag("path-separator").value_name("SEPARATOR").takes_value(true))
+ .arg(flag("pretty").short("p"))
+ .arg(flag("replace").short("r").value_name("ARG").takes_value(true))
+ .arg(flag("case-sensitive").short("s"))
+ .arg(flag("smart-case").short("S"))
+ .arg(flag("sort-files"))
+ .arg(flag("threads")
+ .short("j").value_name("ARG").takes_value(true)
+ .validator(validate_number))
+ .arg(flag("vimgrep"))
+ .arg(flag("type-add")
+ .value_name("TYPE").takes_value(true)
+ .multiple(true).number_of_values(1))
+ .arg(flag("type-clear")
+ .value_name("TYPE").takes_value(true)
+ .multiple(true).number_of_values(1))
+}
+
+struct Usage {
+ short: &'static str,
+ long: &'static str,
+}
+
+macro_rules! doc {
+ ($map:expr, $name:expr, $short:expr) => {
+ doc!($map, $name, $short, $short)
+ };
+ ($map:expr, $name:expr, $short:expr, $long:expr) => {
+ $map.insert($name, Usage {
+ short: $short,
+ long: concat!($long, "\n "),
+ });
+ };
+}
+
+lazy_static! {
+ static ref USAGES: HashMap<&'static str, Usage> = {
+ let mut h = HashMap::new();
+ doc!(h, "help-short",
+ "Show short help output.",
+ "Show short help output. Use --help to show more details.");
+ doc!(h, "help",
+ "Show verbose help output.",
+ "When given, more details about flags are provided.");
+ doc!(h, "version",
+ "Prints version information.");
+
+ doc!(h, "pattern",
+ "A regular expression used for searching.",
+ "A regular expression used for searching. Multiple patterns \
+ may be given. To match a pattern beginning with a -, use [-].");
+ doc!(h, "regexp",
+ "A regular expression used for searching.",
+ "A regular expression used for searching. Multiple patterns \
+ may be given. To match a pattern beginning with a -, use [-].");
+ doc!(h, "path",
+ "A file or directory to search.",
+ "A file or directory to search. Directories are searched \
+ recursively.");
+ doc!(h, "files",
+ "Print each file that would be searched.",
+ "Print each file that would be searched without actually \
+ performing the search. This is useful to determine whether a \
+ particular file is being searched or not.");
+ doc!(h, "type-list",
+ "Show all supported file types.",
+ "Show all supported file types and their corresponding globs.");
+
+ doc!(h, "text",
+ "Search binary files as if they were text.");
+ doc!(h, "count",
+ "Only show count of matches for each file.");
+ doc!(h, "color",
+ "When to use color. [default: auto]",
+ "When to use color in the output. The possible values are \
+ never, auto, always or ansi. The default is auto. When always \
+ is used, coloring is attempted based on your environment. When \
+ ansi used, coloring is forcefully done using ANSI escape color \
+ codes.");
+ doc!(h, "colors",
+ "Configure color settings and styles.",
+ "This flag specifies color settings for use in the output. \
+ This flag may be provided multiple times. Settings are applied \
+ iteratively. Colors are limited to one of eight choices: \
+ red, blue, green, cyan, magenta, yellow, white and black. \
+ Styles are limited to nobold, bold, nointense or intense.\n\n\
+ The format of the flag is {type}:{attribute}:{value}. {type} \
+ should be one of path, line or match. {attribute} can be fg, bg \
+ or style. {value} is either a color (for fg and bg) or a text \
+ style. A special format, {type}:none, will clear all color \
+ settings for {type}.\n\nFor example, the following command will \
+ change the match color to magenta and the background color for \
+ line numbers to yellow:\n\n\
+ rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo.");
+ doc!(h, "fixed-strings",
+ "Treat the pattern as a literal string.",
+ "Treat the pattern as a literal string instead of a regular \
+ expression. When this flag is used, special regular expression \
+ meta characters such as (){}*+. do not need to be escaped.");
+ doc!(h, "glob",
+ "Include or exclude files/directories.",
+ "Include or exclude files/directories for searching that \
+ match the given glob. This always overrides any other \
+ ignore logic. Multiple glob flags may be used. Globbing \
+ rules match .gitignore globs. Precede a glob with a ! \
+ to exclude it.");
+ doc!(h, "ignore-case",
+ "Case insensitive search.",
+ "Case insensitive search. This is overridden by \
+ --case-sensitive.");
+ doc!(h, "line-number",
+ "Show line numbers.",
+ "Show line numbers (1-based). This is enabled by default when \
+ searching in a tty.");
+ doc!(h, "no-line-number",
+ "Suppress line numbers.",
+ "Suppress line numbers. This is enabled by default when NOT \
+ searching in a tty.");
+ doc!(h, "quiet",
+ "Do not print anything to stdout.",
+ "Do not print anything to stdout. If a match is found in a file, \
+ stop searching. This is useful when ripgrep is used only for \
+ its exit code.");
+ doc!(h, "type",
+ "Only search files matching TYPE.",
+ "Only search files matching TYPE. Multiple type flags may be \
+ provided. Use the --type-list flag to list all available \
+ types.");
+ doc!(h, "type-not",
+ "Do not search files matching TYPE.",
+ "Do not search files matching TYPE. Multiple type-not flags may \
+ be provided. Use the --type-list flag to list all available \
+ types.");
+ doc!(h, "unrestricted",
+ "Reduce the level of \"smart\" searching.",
+ "Reduce the level of \"smart\" searching. A single -u \
+ won't respect .gitignore (etc.) files. Two -u flags will \
+ additionally search hidden files and directories. Three \
+ -u flags will additionally search binary files. -uu is \
+ roughly equivalent to grep -r and -uuu is roughly \
+ equivalent to grep -a -r.");
+ doc!(h, "invert-match",
+ "Invert matching.",
+ "Invert matching. Show lines that don't match given patterns.");
+ doc!(h, "word-regexp",
+ "Only show matches surrounded by word boundaries.",
+ "Only show matches surrounded by word boundaries. This is \
+ equivalent to putting \\b before and after all of the search \
+ patterns.");
+
+ doc!(h, "after-context",
+ "Show NUM lines after each match.");
+ doc!(h, "before-context",
+ "Show NUM lines before each match.");
+ doc!(h, "context",
+ "Show NUM lines before and after each match.");
+ doc!(h, "column",
+ "Show column numbers",
+ "Show column numbers (1-based). This only shows the column \
+ numbers for the first match on each line. This does not try \
+ to account for Unicode. One byte is equal to one column. This \
+ implies --line-number.");
+ doc!(h, "context-separator",
+ "Set the context separator string. [default: --]",
+ "The string used to separate non-contiguous context lines in the \
+ output. Escape sequences like \\x7F or \\t may be used. The \
+ default value is --.");
+ doc!(h, "debug",
+ "Show debug messages.",
+ "Show debug messages. Please use this when filing a bug report.");
+ doc!(h, "file",
+ "Search for patterns from the given file.",
+ "Search for patterns from the given file, with one pattern per \
+ line. When this flag is used or multiple times or in \
+ combination with the -e/--regexp flag, then all patterns \
+ provided are searched. Empty pattern lines will match all input \
+ lines, and the newline is not counted as part of the pattern.");
+ doc!(h, "files-with-matches",
+ "Only show the path of each file with at least one match.");
+ doc!(h, "files-without-match",
+ "Only show the path of each file that contains zero matches.");
+ doc!(h, "with-filename",
+ "Show file name for each match.",
+ "Prefix each match with the file name that contains it. This is \
+ the default when more than one file is searched.");
+ doc!(h, "no-filename",
+ "Never show the file name for a match.",
+ "Never show the file name for a match. This is the default when \
+ one file is searched.");
+ doc!(h, "heading",
+ "Show matches grouped by each file.",
+ "This shows the file name above clusters of matches from each \
+ file instead of showing the file name for every match. This is \
+ the default mode at a tty.");
+ doc!(h, "no-heading",
+ "Don't group matches by each file.",
+ "Don't group matches by each file. If -H/--with-filename is \
+ enabled, then file names will be shown for every line matched. \
+ This is the default mode when not at a tty.");
+ doc!(h, "hidden",
+ "Search hidden files and directories.",
+ "Search hidden files and directories. By default, hidden files \
+ and directories are skipped.");
+ doc!(h, "ignore-file",
+ "Specify additional ignore files.",
+ "Specify additional ignore files for filtering file paths. \
+ Ignore files should be in the gitignore format and are matched \
+ relative to the current working directory. These ignore files \
+ have lower precedence than all other ignore files. When \
+ specifying multiple ignore files, earlier files have lower \
+ precedence than later files.");
+ doc!(h, "follow",
+ "Follow symbolic links.");
+ doc!(h, "max-count",
+ "Limit the number of matches.",
+ "Limit the number of matching lines per file searched to NUM.");
+ doc!(h, "maxdepth",
+ "Descend at most NUM directories.",
+ "Limit the depth of directory traversal to NUM levels beyond \
+ the paths given. A value of zero only searches the \
+ starting-points themselves.\n\nFor example, \
+ 'rg --maxdepth 0 dir/' is a no-op because dir/ will not be \
+ descended into. 'rg --maxdepth 1 dir/' will search only the \
+ direct children of dir/.");
+ doc!(h, "mmap",
+ "Searching using memory maps when possible.",
+ "Search using memory maps when possible. This is enabled by \
+ default when ripgrep thinks it will be faster. Note that memory \
+ map searching doesn't currently support all options, so if an \
+ incompatible option (e.g., --context) is given with --mmap, \
+ then memory maps will not be used.");
+ doc!(h, "no-messages",
+ "Suppress all error messages.",
+ "Suppress all error messages. This is equivalent to redirecting \
+ stderr to /dev/null.");
+ doc!(h, "no-mmap",
+ "Never use memory maps.",
+ "Never use memory maps, even when they might be faster.");
+ doc!(h, "no-ignore",
+ "Don't respect ignore files.",
+ "Don't respect ignore files (.gitignore, .ignore, etc.). This \
+ implies --no-ignore-parent and --no-ignore-vcs.");
+ doc!(h, "no-ignore-parent",
+ "Don't respect ignore files in parent directories.",
+ "Don't respect ignore files (.gitignore, .ignore, etc.) in \
+ parent directories.");
+ doc!(h, "no-ignore-vcs",
+ "Don't respect VCS ignore files",
+ "Don't respect version control ignore files (.gitignore, etc.). \
+ This implies --no-ignore-parent. Note that .ignore files will \
+ continue to be respected.");
+ doc!(h, "null",
+ "Print NUL byte after file names",
+ "Whenever a file name is printed, follow it with a NUL byte. \
+ This includes printing file names before matches, and when \
+ printing a list of matching files such as with --count, \
+ --files-with-matches and --files. This option is useful for use \
+ with xargs.");
+ doc!(h, "path-separator",
+ "Path separator to use when printing file paths.",
+ "The path separator to use when printing file paths. This \
+ defaults to your platform's path separator, which is / on Unix \
+ and \\ on Windows. This flag is intended for overriding the \
+ default when the environment demands it (e.g., cygwin). A path \
+ separator is limited to a single byte.");
+ doc!(h, "pretty",
+ "Alias for --color always --heading -n.");
+ doc!(h, "replace",
+ "Replace matches with string given.",
+ "Replace every match with the string given when printing \
+ results. Neither this flag nor any other flag will modify your \
+ files.\n\nCapture group indices (e.g., $5) and names \
+ (e.g., $foo) are supported in the replacement string.\n\n\
+ Note that the replacement by default replaces each match, and \
+ NOT the entire line. To replace the entire line, you should \
+ match the entire line.");
+ doc!(h, "case-sensitive",
+ "Search case sensitively.",
+ "Search case sensitively. This overrides -i/--ignore-case and \
+ -S/--smart-case.");
+ doc!(h, "smart-case",
+ "Smart case search.",
+ "Searches case insensitively if the pattern is all lowercase. \
+ Search case sensitively otherwise. This is overridden by \
+ either -s/--case-sensitive or -i/--ignore-case.");
+ doc!(h, "sort-files",
+ "Sort results by file path. Implies --threads=1.",
+ "Sort results by file path. Note that this currently \
+ disables all parallelism and runs search in a single thread.");
+ doc!(h, "threads",
+ "The approximate number of threads to use.",
+ "The approximate number of threads to use. A value of 0 (which \
+ is the default) causes ripgrep to choose the thread count \
+ using heuristics.");
+ doc!(h, "vimgrep",
+ "Show results in vim compatible format.",
+ "Show results with every match on its own line, including \
+ line numbers and column numbers. With this option, a line with \
+ more than one match will be printed more than once.");
+
+ doc!(h, "type-add",
+ "Add a new glob for a file type.",
+ "Add a new glob for a particular file type. Only one glob can be \
+ added at a time. Multiple --type-add flags can be provided. \
+ Unless --type-clear is used, globs are added to any existing \
+ globs defined inside of ripgrep.\n\nNote that this MUST be \
+ passed to every invocation of ripgrep. Type settings are NOT \
+ persisted.\n\nExample: \
+ rg --type-add 'foo:*.foo' -tfoo PATTERN.\n\n\
+ --type-add can also be used to include rules from other types \
+ with the special include directive. The include directive \
+ permits specifying one or more other type names (separated by a \
+ comma) that have been defined and its rules will automatically \
+ be imported into the type specified. For example, to create a \
+ type called src that matches C++, Python and Markdown files, one \
+ can use:\n\n\
+ --type-add 'src:include:cpp,py,md'\n\n\
+ Additional glob rules can still be added to the src type by \
+ using the --type-add flag again:\n\n\
+ --type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'\n\n\
+ Note that type names must consist only of Unicode letters or \
+ numbers. Punctuation characters are not allowed.");
+ doc!(h, "type-clear",
+ "Clear globs for given file type.",
+ "Clear the file type globs previously defined for TYPE. This \
+ only clears the default type definitions that are found inside \
+ of ripgrep.\n\nNote that this MUST be passed to every \
+ invocation of ripgrep. Type settings are NOT persisted.");
+
+ h
+ };
+}
+
+fn validate_number(s: String) -> Result<(), String> {
+ s.parse::<usize>().map(|_| ()).map_err(|err| err.to_string())
+}
diff --git a/clap/benches/06_rustup.rs b/clap/benches/06_rustup.rs
new file mode 100644
index 0000000..f9ba477
--- /dev/null
+++ b/clap/benches/06_rustup.rs
@@ -0,0 +1,458 @@
+// Used to simulate a fairly large number of subcommands
+//
+// CLI used is from rustup 408ed84f0e50511ed44a405dd91365e5da588790
+
+#![feature(test)]
+
+extern crate clap;
+extern crate test;
+
+use clap::{App, AppSettings, Arg, Shell, SubCommand, ArgGroup};
+
+use test::Bencher;
+
+#[bench]
+fn build_app(b: &mut Bencher) { b.iter(|| build_cli()); }
+
+#[bench]
+fn parse_clean(b: &mut Bencher) { b.iter(|| build_cli().get_matches_from(vec![""])); }
+
+#[bench]
+fn parse_subcommands(b: &mut Bencher) {
+ b.iter(|| build_cli().get_matches_from(vec!["rustup override add stable"]));
+}
+
+pub fn build_cli() -> App<'static, 'static> {
+ App::new("rustup")
+ .version("0.9.0") // Simulating
+ .about("The Rust toolchain installer")
+ .after_help(RUSTUP_HELP)
+ .setting(AppSettings::VersionlessSubcommands)
+ .setting(AppSettings::DeriveDisplayOrder)
+ // .setting(AppSettings::SubcommandRequiredElseHelp)
+ .arg(Arg::with_name("verbose")
+ .help("Enable verbose output")
+ .short("v")
+ .long("verbose"))
+ .subcommand(SubCommand::with_name("show")
+ .about("Show the active and installed toolchains")
+ .after_help(SHOW_HELP))
+ .subcommand(SubCommand::with_name("install")
+ .about("Update Rust toolchains")
+ .after_help(TOOLCHAIN_INSTALL_HELP)
+ .setting(AppSettings::Hidden) // synonym for 'toolchain install'
+ .arg(Arg::with_name("toolchain")
+ .required(true)))
+ .subcommand(SubCommand::with_name("update")
+ .about("Update Rust toolchains")
+ .after_help(UPDATE_HELP)
+ .arg(Arg::with_name("toolchain").required(false))
+ .arg(Arg::with_name("no-self-update")
+ .help("Don't perform self update when running the `rustup` command")
+ .long("no-self-update")
+ .takes_value(false)
+ .hidden(true)))
+ .subcommand(SubCommand::with_name("default")
+ .about("Set the default toolchain")
+ .after_help(DEFAULT_HELP)
+ .arg(Arg::with_name("toolchain").required(true)))
+ .subcommand(SubCommand::with_name("toolchain")
+ .about("Modify or query the installed toolchains")
+ .after_help(TOOLCHAIN_HELP)
+ .setting(AppSettings::VersionlessSubcommands)
+ .setting(AppSettings::DeriveDisplayOrder)
+ // .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("list").about("List installed toolchains"))
+ .subcommand(SubCommand::with_name("install")
+ .about("Install or update a given toolchain")
+ .arg(Arg::with_name("toolchain").required(true)))
+ .subcommand(SubCommand::with_name("uninstall")
+ .about("Uninstall a toolchain")
+ .arg(Arg::with_name("toolchain").required(true)))
+ .subcommand(SubCommand::with_name("link")
+ .about("Create a custom toolchain by symlinking to a directory")
+ .arg(Arg::with_name("toolchain").required(true))
+ .arg(Arg::with_name("path").required(true)))
+ .subcommand(SubCommand::with_name("update")
+ .setting(AppSettings::Hidden) // synonym for 'install'
+ .arg(Arg::with_name("toolchain")
+ .required(true)))
+ .subcommand(SubCommand::with_name("add")
+ .setting(AppSettings::Hidden) // synonym for 'install'
+ .arg(Arg::with_name("toolchain")
+ .required(true)))
+ .subcommand(SubCommand::with_name("remove")
+ .setting(AppSettings::Hidden) // synonym for 'uninstall'
+ .arg(Arg::with_name("toolchain")
+ .required(true))))
+ .subcommand(SubCommand::with_name("target")
+ .about("Modify a toolchain's supported targets")
+ .setting(AppSettings::VersionlessSubcommands)
+ .setting(AppSettings::DeriveDisplayOrder)
+ // .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("list")
+ .about("List installed and available targets")
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true)))
+ .subcommand(SubCommand::with_name("add")
+ .about("Add a target to a Rust toolchain")
+ .arg(Arg::with_name("target").required(true))
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true)))
+ .subcommand(SubCommand::with_name("remove")
+ .about("Remove a target from a Rust toolchain")
+ .arg(Arg::with_name("target").required(true))
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true)))
+ .subcommand(SubCommand::with_name("install")
+ .setting(AppSettings::Hidden) // synonym for 'add'
+ .arg(Arg::with_name("target")
+ .required(true))
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true)))
+ .subcommand(SubCommand::with_name("uninstall")
+ .setting(AppSettings::Hidden) // synonym for 'remove'
+ .arg(Arg::with_name("target")
+ .required(true))
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true))))
+ .subcommand(SubCommand::with_name("component")
+ .about("Modify a toolchain's installed components")
+ .setting(AppSettings::VersionlessSubcommands)
+ .setting(AppSettings::DeriveDisplayOrder)
+ // .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("list")
+ .about("List installed and available components")
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true)))
+ .subcommand(SubCommand::with_name("add")
+ .about("Add a component to a Rust toolchain")
+ .arg(Arg::with_name("component").required(true))
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true))
+ .arg(Arg::with_name("target")
+ .long("target")
+ .takes_value(true)))
+ .subcommand(SubCommand::with_name("remove")
+ .about("Remove a component from a Rust toolchain")
+ .arg(Arg::with_name("component").required(true))
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true))
+ .arg(Arg::with_name("target")
+ .long("target")
+ .takes_value(true))))
+ .subcommand(SubCommand::with_name("override")
+ .about("Modify directory toolchain overrides")
+ .after_help(OVERRIDE_HELP)
+ .setting(AppSettings::VersionlessSubcommands)
+ .setting(AppSettings::DeriveDisplayOrder)
+ // .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("list").about("List directory toolchain overrides"))
+ .subcommand(SubCommand::with_name("set")
+ .about("Set the override toolchain for a directory")
+ .arg(Arg::with_name("toolchain").required(true)))
+ .subcommand(SubCommand::with_name("unset")
+ .about("Remove the override toolchain for a directory")
+ .after_help(OVERRIDE_UNSET_HELP)
+ .arg(Arg::with_name("path")
+ .long("path")
+ .takes_value(true)
+ .help("Path to the directory"))
+ .arg(Arg::with_name("nonexistent")
+ .long("nonexistent")
+ .takes_value(false)
+ .help("Remove override toolchain for all nonexistent directories")))
+ .subcommand(SubCommand::with_name("add")
+ .setting(AppSettings::Hidden) // synonym for 'set'
+ .arg(Arg::with_name("toolchain")
+ .required(true)))
+ .subcommand(SubCommand::with_name("remove")
+ .setting(AppSettings::Hidden) // synonym for 'unset'
+ .about("Remove the override toolchain for a directory")
+ .arg(Arg::with_name("path")
+ .long("path")
+ .takes_value(true))
+ .arg(Arg::with_name("nonexistent")
+ .long("nonexistent")
+ .takes_value(false)
+ .help("Remove override toolchain for all nonexistent directories"))))
+ .subcommand(SubCommand::with_name("run")
+ .about("Run a command with an environment configured for a given toolchain")
+ .after_help(RUN_HELP)
+ .setting(AppSettings::TrailingVarArg)
+ .arg(Arg::with_name("toolchain").required(true))
+ .arg(Arg::with_name("command")
+ .required(true)
+ .multiple(true)
+ .use_delimiter(false)))
+ .subcommand(SubCommand::with_name("which")
+ .about("Display which binary will be run for a given command")
+ .arg(Arg::with_name("command").required(true)))
+ .subcommand(SubCommand::with_name("doc")
+ .about("Open the documentation for the current toolchain")
+ .after_help(DOC_HELP)
+ .arg(Arg::with_name("book")
+ .long("book")
+ .help("The Rust Programming Language book"))
+ .arg(Arg::with_name("std")
+ .long("std")
+ .help("Standard library API documentation"))
+ .group(ArgGroup::with_name("page").args(&["book", "std"])))
+ .subcommand(SubCommand::with_name("man")
+ .about("View the man page for a given command")
+ .arg(Arg::with_name("command").required(true))
+ .arg(Arg::with_name("toolchain")
+ .long("toolchain")
+ .takes_value(true)))
+ .subcommand(SubCommand::with_name("self")
+ .about("Modify the rustup installation")
+ .setting(AppSettings::VersionlessSubcommands)
+ .setting(AppSettings::DeriveDisplayOrder)
+ // .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("update")
+ .about("Download and install updates to rustup"))
+ .subcommand(SubCommand::with_name("uninstall")
+ .about("Uninstall rustup.")
+ .arg(Arg::with_name("no-prompt").short("y")))
+ .subcommand(SubCommand::with_name("upgrade-data")
+ .about("Upgrade the internal data format.")))
+ .subcommand(SubCommand::with_name("telemetry")
+ .about("rustup telemetry commands")
+ .setting(AppSettings::Hidden)
+ .setting(AppSettings::VersionlessSubcommands)
+ .setting(AppSettings::DeriveDisplayOrder)
+ // .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("enable").about("Enable rustup telemetry"))
+ .subcommand(SubCommand::with_name("disable").about("Disable rustup telemetry"))
+ .subcommand(SubCommand::with_name("analyze").about("Analyze stored telemetry")))
+ .subcommand(SubCommand::with_name("set")
+ .about("Alter rustup settings")
+ // .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("default-host")
+ .about("The triple used to identify toolchains when not specified")
+ .arg(Arg::with_name("host_triple").required(true))))
+ .subcommand(SubCommand::with_name("completions")
+ .about("Generate completion scripts for your shell")
+ .after_help(COMPLETIONS_HELP)
+ .setting(AppSettings::ArgRequiredElseHelp)
+ .arg(Arg::with_name("shell").possible_values(&Shell::variants())))
+}
+
+static RUSTUP_HELP: &'static str = r"
+rustup installs The Rust Programming Language from the official
+release channels, enabling you to easily switch between stable, beta,
+and nightly compilers and keep them updated. It makes cross-compiling
+simpler with binary builds of the standard library for common platforms.
+
+If you are new to Rust consider running `rustup doc --book`
+to learn Rust.";
+
+static SHOW_HELP: &'static str = r"
+Shows the name of the active toolchain and the version of `rustc`.
+
+If the active toolchain has installed support for additional
+compilation targets, then they are listed as well.
+
+If there are multiple toolchains installed then all installed
+toolchains are listed as well.";
+
+static UPDATE_HELP: &'static str = r"
+With no toolchain specified, the `update` command updates each of the
+installed toolchains from the official release channels, then updates
+rustup itself.
+
+If given a toolchain argument then `update` updates that toolchain,
+the same as `rustup toolchain install`.
+
+'toolchain' specifies a toolchain name, such as 'stable', 'nightly',
+or '1.8.0'. For more information see `rustup help toolchain`.";
+
+static TOOLCHAIN_INSTALL_HELP: &'static str = r"
+Installs a specific rust toolchain.
+
+The 'install' command is an alias for 'rustup update <toolchain>'.
+
+'toolchain' specifies a toolchain name, such as 'stable', 'nightly',
+or '1.8.0'. For more information see `rustup help toolchain`.";
+
+static DEFAULT_HELP: &'static str = r"
+Sets the default toolchain to the one specified. If the toolchain is
+not already installed then it is installed first.";
+
+static TOOLCHAIN_HELP: &'static str = r"
+Many `rustup` commands deal with *toolchains*, a single installation
+of the Rust compiler. `rustup` supports multiple types of
+toolchains. The most basic track the official release channels:
+'stable', 'beta' and 'nightly'; but `rustup` can also install
+toolchains from the official archives, for alternate host platforms,
+and from local builds.
+
+Standard release channel toolchain names have the following form:
+
+ <channel>[-<date>][-<host>]
+
+ <channel> = stable|beta|nightly|<version>
+ <date> = YYYY-MM-DD
+ <host> = <target-triple>
+
+'channel' is either a named release channel or an explicit version
+number, such as '1.8.0'. Channel names can be optionally appended with
+an archive date, as in 'nightly-2014-12-18', in which case the
+toolchain is downloaded from the archive for that date.
+
+Finally, the host may be specified as a target triple. This is most
+useful for installing a 32-bit compiler on a 64-bit platform, or for
+installing the [MSVC-based toolchain] on Windows. For example:
+
+ rustup toolchain install stable-x86_64-pc-windows-msvc
+
+For convenience, elements of the target triple that are omitted will be
+inferred, so the above could be written:
+
+ $ rustup default stable-msvc
+
+Toolchain names that don't name a channel instead can be used to name
+custom toolchains with the `rustup toolchain link` command.";
+
+static OVERRIDE_HELP: &'static str = r"
+Overrides configure rustup to use a specific toolchain when
+running in a specific directory.
+
+Directories can be assigned their own Rust toolchain with
+`rustup override`. When a directory has an override then
+any time `rustc` or `cargo` is run inside that directory,
+or one of its child directories, the override toolchain
+will be invoked.
+
+To pin to a specific nightly:
+
+ rustup override set nightly-2014-12-18
+
+Or a specific stable release:
+
+ rustup override set 1.0.0
+
+To see the active toolchain use `rustup show`. To remove the override
+and use the default toolchain again, `rustup override unset`.";
+
+static OVERRIDE_UNSET_HELP: &'static str = r"
+If `--path` argument is present, removes the override toolchain for
+the specified directory. If `--nonexistent` argument is present, removes
+the override toolchain for all nonexistent directories. Otherwise,
+removes the override toolchain for the current directory.";
+
+static RUN_HELP: &'static str = r"
+Configures an environment to use the given toolchain and then runs
+the specified program. The command may be any program, not just
+rustc or cargo. This can be used for testing arbitrary toolchains
+without setting an override.
+
+Commands explicitly proxied by `rustup` (such as `rustc` and `cargo`)
+also have a shorthand for this available. The toolchain can be set by
+using `+toolchain` as the first argument. These are equivalent:
+
+ cargo +nightly build
+
+ rustup run nightly cargo build";
+
+static DOC_HELP: &'static str = r"
+Opens the documentation for the currently active toolchain with the
+default browser.
+
+By default, it opens the documentation index. Use the various flags to
+open specific pieces of documentation.";
+
+static COMPLETIONS_HELP: &'static str = r"
+One can generate a completion script for `rustup` that is compatible with
+a given shell. The script is output on `stdout` allowing one to re-direct
+the output to the file of their choosing. Where you place the file will
+depend on which shell, and which operating system you are using. Your
+particular configuration may also determine where these scripts need
+to be placed.
+
+Here are some common set ups for the three supported shells under
+Unix and similar operating systems (such as GNU/Linux).
+
+BASH:
+
+Completion files are commonly stored in `/usr/share/bash-completion/completions`
+
+Run the command:
+
+`rustup completions bash > /usr/share/bash-completion/completions/rustup.bash`
+
+This installs the completion script. You may have to log out and log
+back in to your shell session for the changes to take affect.
+
+FISH:
+
+Fish completion files are commonly stored in
+`$HOME/.config/fish/completions`
+
+Run the command:
+`rustup completions fish > ~/.config/fish/completions/rustup.fish`
+
+This installs the completion script. You may have to log out and log
+back in to your shell session for the changes to take affect.
+
+ZSH:
+
+ZSH completions are commonly stored in any directory listed in your
+`$fpath` variable. To use these completions, you must either add the
+generated script to one of those directories, or add your own
+to this list.
+
+Adding a custom directory is often the safest best if you're unsure
+of which directory to use. First create the directory, for this
+example we'll create a hidden directory inside our `$HOME` directory
+
+`mkdir ~/.zfunc`
+
+Then add the following lines to your `.zshrc` just before `compinit`
+
+`fpath+=~/.zfunc`
+
+Now you can install the completions script using the following command
+
+`rustup completions zsh > ~/.zfunc/_rustup`
+
+You must then either log out and log back in, or simply run
+
+`exec zsh`
+
+For the new completions to take affect.
+
+CUSTOM LOCATIONS:
+
+Alternatively, you could save these files to the place of your choosing,
+such as a custom directory inside your $HOME. Doing so will require you
+to add the proper directives, such as `source`ing inside your login
+script. Consult your shells documentation for how to add such directives.
+
+POWERSHELL:
+
+The powershell completion scripts require PowerShell v5.0+ (which comes
+Windows 10, but can be downloaded separately for windows 7 or 8.1).
+
+First, check if a profile has already been set
+
+`PS C:\> Test-Path $profile`
+
+If the above command returns `False` run the following
+
+`PS C:\> New-Item -path $profile -type file --force`
+
+Now open the file provided by `$profile` (if you used the `New-Item` command
+it will be `%USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`
+
+Next, we either save the completions file into our profile, or into a separate file
+and source it inside our profile. To save the completions into our profile simply
+use";
diff --git a/clap/clap-perf/clap_perf.dat b/clap/clap-perf/clap_perf.dat
new file mode 100644
index 0000000..6a8592c
--- /dev/null
+++ b/clap/clap-perf/clap_perf.dat
@@ -0,0 +1,8 @@
+#Version Date Builder Err Usage Err Parse1 Err Parse2 Err
+1.0 2015-07-07 12408 840 16830 229 21235 725 27387 910
+1.1 2015-07-16 11885 191 16670 595 20919 252 26868 457
+1.2 2015-08-14 12563 587 17190 311 22421 233 28232 624
+1.3 2015-09-01 10534 131 14648 874 18213 1070 24101 361
+1.4 2015-09-09 10223 852 13203 749 18924 1216 23492 944
+1.5 2015-11-12 5422 416 7974 680 9723 792 13389 1151
+2.0 2016-01-27 4783 376 5263 481 9651 1015 10577 191
diff --git a/clap/clap-perf/clap_perf.png b/clap/clap-perf/clap_perf.png
new file mode 100644
index 0000000..caaefb0
--- /dev/null
+++ b/clap/clap-perf/clap_perf.png
Binary files differ
diff --git a/clap/clap-perf/plot_perf.gp b/clap/clap-perf/plot_perf.gp
new file mode 100755
index 0000000..4db6a87
--- /dev/null
+++ b/clap/clap-perf/plot_perf.gp
@@ -0,0 +1,26 @@
+#!/usr/bin/gnuplot
+reset
+set terminal png
+set output "clap_perf.png"
+
+set xlabel "Version"
+set xrange [0.9:2.1]
+set ylabel "Time (ns)"
+set yrange [0:35000]
+
+set title "clap-rs Performance (Parse Time - Lower is Better) by Version"
+set key inside right top
+set grid
+set style line 1 lc rgb '#0060ad' lt 1 lw 1 pt 7 ps .5 # --- blue
+set style line 2 lc rgb '#dd181f' lt 1 lw 1 pt 5 ps .5 # --- red
+set style line 3 lc rgb '#18dd00' lt 1 lw 1 pt 7 ps .5 # --- green
+set style line 4 lc rgb '#000000' lt 1 lw 1 pt 5 ps .5 # --- black
+
+plot "clap_perf.dat" u 1:3:4 notitle w yerrorbars ls 1, \
+ "" u 1:3 t "Create Parser Using Builder" w lines ls 1, \
+ "" u 1:5:6 notitle w yerrorbars ls 2, \
+ "" u 1:5 t "Create Parser Usage String" w lines ls 2, \
+ "" u 1:7:8 notitle "Parse Complex Args" w yerrorbars ls 3, \
+ "" u 1:7 t "Parse Complex Args" w lines ls 3, \
+ "" u 1:9:10 notitle w yerrorbars ls 4, \
+ "" u 1:9 t "Parse Very Complex Args" w lines ls 4
diff --git a/clap/clap-test.rs b/clap/clap-test.rs
new file mode 100644
index 0000000..7d57ac4
--- /dev/null
+++ b/clap/clap-test.rs
@@ -0,0 +1,86 @@
+#[allow(unused_imports, dead_code)]
+mod test {
+ use std::str;
+ use std::io::{Cursor, Write};
+
+ use regex::Regex;
+
+ use clap::{App, Arg, SubCommand, ArgGroup};
+
+ fn compare<S, S2>(l: S, r: S2) -> bool
+ where S: AsRef<str>,
+ S2: AsRef<str>
+ {
+ let re = Regex::new("\x1b[^m]*m").unwrap();
+ // Strip out any mismatching \r character on windows that might sneak in on either side
+ let ls = l.as_ref().trim().replace("\r", "");
+ let rs = r.as_ref().trim().replace("\r", "");
+ let left = re.replace_all(&*ls, "");
+ let right = re.replace_all(&*rs, "");
+ let b = left == right;
+ if !b {
+ println!();
+ println!("--> left");
+ println!("{}", left);
+ println!("--> right");
+ println!("{}", right);
+ println!("--")
+ }
+ b
+ }
+
+ pub fn compare_output(l: App, args: &str, right: &str, stderr: bool) -> bool {
+ let mut buf = Cursor::new(Vec::with_capacity(50));
+ let res = l.get_matches_from_safe(args.split(' ').collect::<Vec<_>>());
+ let err = res.unwrap_err();
+ err.write_to(&mut buf).unwrap();
+ let content = buf.into_inner();
+ let left = String::from_utf8(content).unwrap();
+ assert_eq!(stderr, err.use_stderr());
+ compare(left, right)
+ }
+ pub fn compare_output2(l: App, args: &str, right1: &str, right2: &str, stderr: bool) -> bool {
+ let mut buf = Cursor::new(Vec::with_capacity(50));
+ let res = l.get_matches_from_safe(args.split(' ').collect::<Vec<_>>());
+ let err = res.unwrap_err();
+ err.write_to(&mut buf).unwrap();
+ let content = buf.into_inner();
+ let left = String::from_utf8(content).unwrap();
+ assert_eq!(stderr, err.use_stderr());
+ compare(&*left, right1) || compare(&*left, right2)
+ }
+
+ // Legacy tests from the Python script days
+
+ pub fn complex_app() -> App<'static, 'static> {
+ let args = "-o --option=[opt]... 'tests options'
+ [positional] 'tests positionals'";
+ let opt3_vals = ["fast", "slow"];
+ let pos3_vals = ["vi", "emacs"];
+ App::new("clap-test")
+ .version("v1.4.8")
+ .about("tests clap library")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .args_from_usage(args)
+ .arg(Arg::from_usage("-f --flag... 'tests flags'")
+ .global(true))
+ .args(&[
+ Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("long-option-2"),
+ Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"),
+ Arg::from_usage("[positional2] 'tests positionals with exclusions'"),
+ Arg::from_usage("-O --Option [option3] 'specific vals'").possible_values(&opt3_vals),
+ Arg::from_usage("[positional3]... 'tests specific values'").possible_values(&pos3_vals),
+ Arg::from_usage("--multvals [one] [two] 'Tests multiple values, not mult occs'"),
+ Arg::from_usage("--multvalsmo... [one] [two] 'Tests multiple values, and mult occs'"),
+ Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2),
+ Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3)
+ ])
+ .subcommand(SubCommand::with_name("subcmd")
+ .about("tests subcommands")
+ .version("0.1")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .arg_from_usage("-o --option [scoption]... 'tests options'")
+ .arg_from_usage("-s --subcmdarg [subcmdarg] 'tests other args'")
+ .arg_from_usage("[scpositional] 'tests positionals'"))
+ }
+}
diff --git a/clap/clap_dep_graph.dot b/clap/clap_dep_graph.dot
new file mode 100644
index 0000000..9d7e5c6
--- /dev/null
+++ b/clap/clap_dep_graph.dot
@@ -0,0 +1,41 @@
+digraph dependencies {
+ N0[label="clap"];
+ N1[label="ansi_term"];
+ N2[label="bitflags"];
+ N3[label="clippy",color=blue];
+ N4[label="strsim"];
+ N5[label="term_size"];
+ N6[label="unicode-segmentation"];
+ N7[label="unicode-width"];
+ N8[label="vec_map"];
+ N9[label="yaml-rust",color=red];
+ N10[label="clippy_lints",color=blue];
+ N11[label="matches",color=blue];
+ N12[label="quine-mc_cluskey",color=blue];
+ N13[label="regex-syntax",color=red];
+ N14[label="rustc-serialize",color=blue];
+ N15[label="semver",color=blue];
+ N16[label="toml",color=blue];
+ N17[label="unicode-normalization",color=blue];
+ N0 -> N1[label="",style=dashed];
+ N0 -> N2[label=""];
+ N0 -> N3[label="",style=dashed,color=blue];
+ N0 -> N4[label="",style=dashed];
+ N0 -> N5[label="",style=dashed];
+ N0 -> N6[label=""];
+ N0 -> N7[label=""];
+ N0 -> N8[label=""];
+ N0 -> N9[label="",style=dashed,color=red];
+ N3 -> N10[label="",style=dashed,color=blue];
+ N5 -> N3[label="",style=dashed,color=blue];
+ N9 -> N3[label="",style=dashed,color=blue];
+ N9 -> N13[label="",style=dashed,color=red];
+ N10 -> N11[label="",style=dashed,color=blue];
+ N10 -> N12[label="",style=dashed,color=blue];
+ N10 -> N13[label="",style=dashed,color=blue];
+ N10 -> N14[label="",style=dashed,color=blue];
+ N10 -> N15[label="",style=dashed,color=blue];
+ N10 -> N16[label="",style=dashed,color=blue];
+ N10 -> N17[label="",style=dashed,color=blue];
+ N16 -> N14[label="",style=dashed,color=blue];
+}
diff --git a/clap/clap_dep_graph.png b/clap/clap_dep_graph.png
new file mode 100644
index 0000000..8290d6f
--- /dev/null
+++ b/clap/clap_dep_graph.png
Binary files differ
diff --git a/clap/examples/01a_quick_example.rs b/clap/examples/01a_quick_example.rs
new file mode 100644
index 0000000..c7fa20f
--- /dev/null
+++ b/clap/examples/01a_quick_example.rs
@@ -0,0 +1,79 @@
+extern crate clap;
+
+use clap::{App, SubCommand};
+
+fn main() {
+
+ // This example shows how to create an application with several arguments using usage strings, which can be
+ // far less verbose that shown in 01b_QuickExample.rs, but is more readable. The downside is you cannot set
+ // the more advanced configuration options using this method (well...actually you can, you'll see ;) )
+ //
+ // The example below is functionally identical to the 01b_quick_example.rs and 01c_quick_example.rs
+ //
+ // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated)
+ // - A config file
+ // + Uses "-c filename" or "--config filename"
+ // - An output file
+ // + A positional argument (i.e. "$ myapp output_filename")
+ // - A debug flag
+ // + Uses "-d" or "--debug"
+ // + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example)
+ // - A help flag (automatically generated by clap)
+ // + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help")
+ // - A version flag (automatically generated by clap)
+ // + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version")
+ // - A subcommand "test" (subcommands behave like their own apps, with their own arguments
+ // + Used by "$ myapp test" with the following arguments
+ // > A list flag
+ // = Uses "-l" (usage is "$ myapp test -l"
+ // > A help flag (automatically generated by clap
+ // = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help")
+ // > A version flag (automatically generated by clap
+ // = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version")
+ // - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
+ // + Used by "$ myapp help" (same functionality as "-h" or "--help")
+ let matches = App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .args_from_usage("-c, --config=[FILE] 'Sets a custom config file'
+ <output> 'Sets an optional output file'
+ -d... 'Turn debugging information on'")
+ .subcommand(SubCommand::with_name("test")
+ .about("does testing things")
+ .arg_from_usage("-l, --list 'lists test values'"))
+ .get_matches();
+
+ // You can check the value provided by positional arguments, or option arguments
+ if let Some(o) = matches.value_of("output") {
+ println!("Value for output: {}", o);
+ }
+
+ if let Some(c) = matches.value_of("config") {
+ println!("Value for config: {}", c);
+ }
+
+ // You can see how many times a particular flag or argument occurred
+ // Note, only flags can have multiple occurrences
+ match matches.occurrences_of("d") {
+ 0 => println!("Debug mode is off"),
+ 1 => println!("Debug mode is kind of on"),
+ 2 => println!("Debug mode is on"),
+ 3 | _ => println!("Don't be crazy"),
+ }
+
+ // You can check for the existence of subcommands, and if found use their
+ // matches just as you would the top level app
+ if let Some(matches) = matches.subcommand_matches("test") {
+ // "$ myapp test" was run
+ if matches.is_present("list") {
+ // "$ myapp test -l" was run
+ println!("Printing testing lists...");
+ } else {
+ println!("Not printing testing lists...");
+ }
+ }
+
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/01b_quick_example.rs b/clap/examples/01b_quick_example.rs
new file mode 100644
index 0000000..7f455a8
--- /dev/null
+++ b/clap/examples/01b_quick_example.rs
@@ -0,0 +1,93 @@
+extern crate clap;
+
+use clap::{App, Arg, SubCommand};
+
+fn main() {
+
+ // This method shows the traditional, and slightly more configurable way to set up arguments. This method is
+ // more verbose, but allows setting more configuration options, and even supports easier dynamic generation.
+ //
+ // The example below is functionally identical to the 01a_quick_example.rs and 01c_quick_example.rs
+ //
+ // *NOTE:* You can actually achieve the best of both worlds by using Arg::from_usage() (instead of Arg::with_name())
+ // and *then* setting any additional properties.
+ //
+ // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated)
+ // - A config file
+ // + Uses "-c filename" or "--config filename"
+ // - An output file
+ // + A positional argument (i.e. "$ myapp output_filename")
+ // - A debug flag
+ // + Uses "-d" or "--debug"
+ // + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example)
+ // - A help flag (automatically generated by clap)
+ // + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help")
+ // - A version flag (automatically generated by clap)
+ // + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version")
+ // - A subcommand "test" (subcommands behave like their own apps, with their own arguments
+ // + Used by "$ myapp test" with the following arguments
+ // > A list flag
+ // = Uses "-l" (usage is "$ myapp test -l"
+ // > A help flag (automatically generated by clap
+ // = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help")
+ // > A version flag (automatically generated by clap
+ // = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version")
+ // - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
+ // + Used by "$ myapp help" (same functionality as "-h" or "--help")
+ let matches = App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .arg(Arg::with_name("config")
+ .short("c")
+ .long("config")
+ .value_name("FILE")
+ .help("Sets a custom config file")
+ .takes_value(true))
+ .arg(Arg::with_name("output")
+ .help("Sets an optional output file")
+ .index(1))
+ .arg(Arg::with_name("debug")
+ .short("d")
+ .multiple(true)
+ .help("Turn debugging information on"))
+ .subcommand(SubCommand::with_name("test")
+ .about("does testing things")
+ .arg(Arg::with_name("list")
+ .short("l")
+ .help("lists test values")))
+ .get_matches();
+
+ // You can check the value provided by positional arguments, or option arguments
+ if let Some(o) = matches.value_of("output") {
+ println!("Value for output: {}", o);
+ }
+
+ if let Some(c) = matches.value_of("config") {
+ println!("Value for config: {}", c);
+ }
+
+ // You can see how many times a particular flag or argument occurred
+ // Note, only flags can have multiple occurrences
+ match matches.occurrences_of("debug") {
+ 0 => println!("Debug mode is off"),
+ 1 => println!("Debug mode is kind of on"),
+ 2 => println!("Debug mode is on"),
+ 3 | _ => println!("Don't be crazy"),
+ }
+
+ // You can check for the existence of subcommands, and if found use their
+ // matches just as you would the top level app
+ if let Some(matches) = matches.subcommand_matches("test") {
+ // "$ myapp test" was run
+ if matches.is_present("list") {
+ // "$ myapp test -l" was run
+ println!("Printing testing lists...");
+ } else {
+ println!("Not printing testing lists...");
+ }
+ }
+
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/01c_quick_example.rs b/clap/examples/01c_quick_example.rs
new file mode 100644
index 0000000..071bdc0
--- /dev/null
+++ b/clap/examples/01c_quick_example.rs
@@ -0,0 +1,75 @@
+#[macro_use]
+extern crate clap;
+
+fn main() {
+ // This example shows how to create an application with several arguments using macro builder.
+ // It combines the simplicity of the from_usage methods and the performance of the Builder Pattern.
+ //
+ // The example below is functionally identical to the one in 01a_quick_example.rs and 01b_quick_example.rs
+ //
+ // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated)
+ // - A config file
+ // + Uses "-c filename" or "--config filename"
+ // - An output file
+ // + A positional argument (i.e. "$ myapp output_filename")
+ // - A debug flag
+ // + Uses "-d" or "--debug"
+ // + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example)
+ // - A help flag (automatically generated by clap)
+ // + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help")
+ // - A version flag (automatically generated by clap)
+ // + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version")
+ // - A subcommand "test" (subcommands behave like their own apps, with their own arguments
+ // + Used by "$ myapp test" with the following arguments
+ // > A list flag
+ // = Uses "-l" (usage is "$ myapp test -l"
+ // > A help flag (automatically generated by clap
+ // = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help")
+ // > A version flag (automatically generated by clap
+ // = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version")
+ // - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
+ // + Used by "$ myapp help" (same functionality as "-h" or "--help")
+ let matches = clap_app!(myapp =>
+ (version: "1.0")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (about: "Does awesome things")
+ (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
+ (@arg INPUT: +required "Sets the input file to use")
+ (@arg debug: -d ... "Sets the level of debugging information")
+ (@subcommand test =>
+ (about: "controls testing features")
+ (version: "1.3")
+ (author: "Someone E. <someone_else@other.com>")
+ (@arg verbose: -v --verbose "Print test information verbosely")
+ )
+ ).get_matches();
+
+ // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
+ // required we could have used an 'if let' to conditionally get the value)
+ println!("Using input file: {}", matches.value_of("INPUT").unwrap());
+
+ // Gets a value for config if supplied by user, or defaults to "default.conf"
+ let config = matches.value_of("CONFIG").unwrap_or("default.conf");
+ println!("Value for config: {}", config);
+
+ // Vary the output based on how many times the user used the "debug" flag
+ // (i.e. 'myapp -d -d -d' or 'myapp -ddd' vs 'myapp -d'
+ match matches.occurrences_of("debug") {
+ 0 => println!("Debug mode is off"),
+ 1 => println!("Debug mode is kind of on"),
+ 2 => println!("Debug mode is on"),
+ 3 | _ => println!("Don't be crazy"),
+ }
+
+ // You can information about subcommands by requesting their matches by name
+ // (as below), requesting just the name used, or both at the same time
+ if let Some(matches) = matches.subcommand_matches("test") {
+ if matches.is_present("verbose") {
+ println!("Printing verbosely...");
+ } else {
+ println!("Printing normally...");
+ }
+ }
+
+ // more program logic goes here...
+}
diff --git a/clap/examples/02_apps.rs b/clap/examples/02_apps.rs
new file mode 100644
index 0000000..8e45640
--- /dev/null
+++ b/clap/examples/02_apps.rs
@@ -0,0 +1,30 @@
+extern crate clap;
+
+use clap::App;
+
+fn main() {
+ // Apps describe the top level application
+ //
+ // You create an App and set various options on that App using the "builder pattern"
+ //
+ // The options (version(), author(), about()) aren't mandatory, but recommended. There is
+ // another option, usage(), which is an exception to the rule. This should only be used when
+ // the default usage string automatically generated by clap doesn't suffice.
+ //
+ // You also set all the valid arguments your App should accept via the arg(), args(), arg_from_usage()
+ // and args_from_usage() (as well as subcommands via the subcommand() and subcommands() methods) which
+ // will be covered later.
+ //
+ // Once all options have been set, call one of the .get_matches* family of methods in order to
+ // start the parsing and find all valid command line arguments that supplied by the user at
+ // runtime. The name given to new() will be displayed when the version or help flags are used.
+ App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .get_matches();
+
+ // This example doesn't do much, but it *does* give automatic -h, --help, -V, and --version functionality ;)
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/03_args.rs b/clap/examples/03_args.rs
new file mode 100644
index 0000000..c62d576
--- /dev/null
+++ b/clap/examples/03_args.rs
@@ -0,0 +1,84 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+fn main() {
+ // Args describe a possible valid argument which may be supplied by the user at runtime. There
+ // are three different types of arguments (flags, options, and positional) as well as a fourth
+ // special type of argument, called SubCommands (which will be discussed separately).
+ //
+ // Args are described in the same manner as Apps using the "builder pattern" with multiple
+ // methods describing various settings for the individual arguments. Or by supplying a "usage"
+ // string. Both methods have their pros and cons.
+ //
+ // Arguments can be added to applications in two manners, one at a time with the arg(), and
+ // arg_from_usage() method, or multiple arguments at once via a Vec<Arg> inside the args() method,
+ // or a single &str describing multiple Args (one per line) supplied to args_from_usage().
+ //
+ // There are various options which can be set for a given argument, some apply to any of the
+ // three types of arguments, some only apply one or two of the types. *NOTE* if you set
+ // incompatible options on a single argument, clap will panic! at runtime. This is by design,
+ // so that you know right away an error was made by the developer, not the end user.
+ //
+ // # Help and Version
+ // clap automatically generates a help and version flag for you, unless you specify your
+ // own. By default help uses "-h" and "--help", and version uses "-V" and "--version". You can
+ // safely override "-V" and "-h" to your own arguments, and "--help" and "--version" will still
+ // be automatically generated for you.
+ let matches = App::new("MyApp")
+ // All application settings go here...
+
+ // A simple "Flag" argument example (i.e. "-d") using the builder pattern
+ .arg(Arg::with_name("debug")
+ .help("turn on debugging information")
+ .short("d"))
+
+ // Two arguments, one "Option" argument (i.e. one that takes a value) such
+ // as "-c some", and one positional argument (i.e. "myapp some_file")
+ .args(&[
+ Arg::with_name("config")
+ .help("sets the config file to use")
+ .takes_value(true)
+ .short("c")
+ .long("config"),
+ Arg::with_name("input")
+ .help("the input file to use")
+ .index(1)
+ .required(true)
+ ])
+
+ // *Note* the following two examples are convenience methods, if you wish
+ // to still get the full configurability of Arg::with_name() and the readability
+ // of arg_from_usage(), you can instantiate a new Arg with Arg::from_usage() and
+ // still be able to set all the additional properties, just like Arg::with_name()
+ //
+ //
+ // One "Flag" using a usage string
+ .arg_from_usage("--license 'display the license file'")
+
+ // Two args, one "Positional", and one "Option" using a usage string
+ .args_from_usage("[output] 'Supply an output file to use'
+ -i, --int=[IFACE] 'Set an interface to use'")
+ .get_matches();
+
+ // Here are some examples of using the arguments defined above. Keep in mind that this is only
+ // an example, and may be somewhat contrived
+ //
+ // First we check if debugging should be on or not
+ println!("Debugging mode is: {}", if matches.is_present("debug") { "ON" } else { "OFF" });
+
+ // Next we print the config file we're using, if any was defined with either -c <file> or
+ // --config <file>
+ if let Some(config) = matches.value_of("config") {
+ println!("A config file was passed in: {}", config);
+ }
+
+ // Let's print the <INPUT> file the user passed in. We can use .unwrap() here becase the arg is
+ // required, and parsing would have failed if the user forgot it
+ println!("Using input file: {}", matches.value_of("input").unwrap());
+
+ // We could continue checking for and using arguments in this manner, such as "license",
+ // "output", and "interface". Keep in mind that "output" and "interface" are optional, so you
+ // shouldn't call .unwrap(). Instead, prefer using an 'if let' expression as we did with
+ // "config"
+}
diff --git a/clap/examples/04_using_matches.rs b/clap/examples/04_using_matches.rs
new file mode 100644
index 0000000..a0a986f
--- /dev/null
+++ b/clap/examples/04_using_matches.rs
@@ -0,0 +1,54 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+fn main() {
+
+ // Once all App settings (including all arguments) have been set, you call get_matches() which
+ // parses the string provided by the user, and returns all the valid matches to the ones you
+ // specified.
+ //
+ // You can then query the matches struct to get information about how the user ran the program
+ // at startup.
+ //
+ // For this example, let's assume you created an App which accepts three arguments (plus two
+ // generated by clap), a flag to display debugging information triggered with "-d" or
+ // "--debug" as well as an option argument which specifies a custom configuration file to use
+ // triggered with "-c file" or "--config file" or "--config=file" and finally a positional
+ // argument which is the input file we want to work with, this will be the only required
+ // argument.
+ let matches = App::new("MyApp")
+ .about("Parses an input file to do awesome things")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .arg(Arg::with_name("debug")
+ .help("turn on debugging information")
+ .short("d")
+ .long("debug"))
+ .arg(Arg::with_name("config")
+ .help("sets the config file to use")
+ .short("c")
+ .long("config"))
+ .arg(Arg::with_name("input")
+ .help("the input file to use")
+ .index(1)
+ .required(true))
+ .get_matches();
+
+ // We can find out whether or not debugging was turned on
+ if matches.is_present("debug") {
+ println!("Debugging is turned on");
+ }
+
+ // If we wanted to do some custom initialization based off some configuration file
+ // provided by the user, we could get the file (A string of the file)
+ if let Some(file) = matches.value_of("config") {
+ println!("Using config file: {}", file);
+ }
+
+ // Because "input" is required we can safely call unwrap() because had the user NOT
+ // specified a value, clap would have explained the error the user, and exited.
+ println!("Doing real work with file: {}", matches.value_of("input").unwrap() );
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/05_flag_args.rs b/clap/examples/05_flag_args.rs
new file mode 100644
index 0000000..a6b8945
--- /dev/null
+++ b/clap/examples/05_flag_args.rs
@@ -0,0 +1,56 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+fn main() {
+
+ // Of the three argument types, flags are the most simple. Flags are simple switches which can
+ // be either "on" or "off"
+ //
+ // clap also supports multiple occurrences of flags, the common example is "verbosity" where a
+ // user could want a little information with "-v" or tons of information with "-v -v" or "-vv"
+ let matches = App::new("MyApp")
+ // Regular App configuration goes here...
+
+ // We'll add a flag that represents an awesome meter...
+ //
+ // I'll explain each possible setting that "flags" accept. Keep in mind
+ // that you DO NOT need to set each of these for every flag, only the ones
+ // you want for your individual case.
+ .arg(Arg::with_name("awesome")
+ .help("turns up the awesome") // Displayed when showing help info
+ .short("a") // Trigger this arg with "-a"
+ .long("awesome") // Trigger this arg with "--awesome"
+ .multiple(true) // This flag should allow multiple
+ // occurrences such as "-aaa" or "-a -a"
+ .requires("config") // Says, "If the user uses -a, they MUST
+ // also use this other 'config' arg too"
+ // Can also specify a list using
+ // requires_all(Vec<&str>)
+ .conflicts_with("output") // Opposite of requires(), says "if the
+ // user uses -a, they CANNOT use 'output'"
+ // also has a conflicts_with_all(Vec<&str>)
+ )
+ // NOTE: In order to compile this example, comment out requires() and
+ // conflicts_with() because we have not defined an "output" or "config"
+ // argument.
+ .get_matches();
+
+ // We can find out whether or not awesome was used
+ if matches.is_present("awesome") {
+ println!("Awesomeness is turned on");
+ }
+
+ // If we set the multiple() option of a flag we can check how many times the user specified
+ //
+ // Note: if we did not specify the multiple() option, and the user used "awesome" we would get
+ // a 1 (no matter how many times they actually used it), or a 0 if they didn't use it at all
+ match matches.occurrences_of("awesome") {
+ 0 => println!("Nothing is awesome"),
+ 1 => println!("Some things are awesome"),
+ 2 => println!("Lots of things are awesome"),
+ 3 | _ => println!("EVERYTHING is awesome!"),
+ }
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/06_positional_args.rs b/clap/examples/06_positional_args.rs
new file mode 100644
index 0000000..1f29612
--- /dev/null
+++ b/clap/examples/06_positional_args.rs
@@ -0,0 +1,56 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+fn main() {
+
+ // Positional arguments are those values after the program name which are not preceded by any
+ // identifier (such as "myapp some_file"). Positionals support many of the same options as
+ // flags, as well as a few additional ones.
+ let matches = App::new("MyApp")
+ // Regular App configuration goes here...
+
+ // We'll add two positional arguments, a input file, and a config file.
+ //
+ // I'll explain each possible setting that "positionals" accept. Keep in
+ // mind that you DO NOT need to set each of these for every flag, only the
+ // ones that apply to your individual case.
+ .arg(Arg::with_name("input")
+ .help("the input file to use") // Displayed when showing help info
+ .index(1) // Set the order in which the user must
+ // specify this argument (Starts at 1)
+ .requires("config") // Says, "If the user uses "input", they MUST
+ // also use this other 'config' arg too"
+ // Can also specify a list using
+ // requires_all(Vec<&str>)
+ .conflicts_with("output") // Opposite of requires(), says "if the
+ // user uses -a, they CANNOT use 'output'"
+ // also has a conflicts_with_all(Vec<&str>)
+ .required(true) // By default this argument MUST be present
+ // NOTE: mutual exclusions take precedence over
+ // required arguments
+ )
+ .arg(Arg::with_name("config")
+ .help("the config file to use")
+ .index(2)) // Note, we do not need to specify required(true)
+ // if we don't want to, because "input" already
+ // requires "config"
+ // Note, we also do not need to specify requires("input")
+ // because requires lists are automatically two-way
+
+ // NOTE: In order to compile this example, comment out conflicts_with()
+ // because we have not defined an "output" argument.
+ .get_matches();
+
+ // We can find out whether or not "input" or "config" were used
+ if matches.is_present("input") {
+ println!("An input file was specified");
+ }
+
+ // We can also get the values for those arguments
+ if let Some(in_file) = matches.value_of("input") {
+ // It's safe to call unwrap() because of the required options we set above
+ println!("Doing work with {} and {}", in_file, matches.value_of("config").unwrap());
+ }
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/07_option_args.rs b/clap/examples/07_option_args.rs
new file mode 100644
index 0000000..85ff0e5
--- /dev/null
+++ b/clap/examples/07_option_args.rs
@@ -0,0 +1,71 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+fn main() {
+
+ // Option arguments are those that take an additional value, such as "-c value". In clap they
+ // support three types of specification, those with short() as "-o some", or those with long()
+ // as "--option value" or "--option=value"
+ //
+ // Options also support a multiple setting, which is discussed in the example below.
+ let matches = App::new("MyApp")
+ // Regular App configuration goes here...
+
+ // Assume we have an application that accepts an input file via the "-i file"
+ // or the "--input file" (as well as "--input=file").
+ // Below every setting supported by option arguments is discussed.
+ // NOTE: You DO NOT need to specify each setting, only those which apply
+ // to your particular case.
+ .arg(Arg::with_name("input")
+ .help("the input file to use") // Displayed when showing help info
+ .takes_value(true) // MUST be set to true in order to be an "option" argument
+ .short("i") // This argument is triggered with "-i"
+ .long("input") // This argument is triggered with "--input"
+ .multiple(true) // Set to true if you wish to allow multiple occurrences
+ // such as "-i file -i other_file -i third_file"
+ .required(true) // By default this argument MUST be present
+ // NOTE: mutual exclusions take precedence over
+ // required arguments
+ .requires("config") // Says, "If the user uses "input", they MUST
+ // also use this other 'config' arg too"
+ // Can also specify a list using
+ // requires_all(Vec<&str>)
+ .conflicts_with("output") // Opposite of requires(), says "if the
+ // user uses -a, they CANNOT use 'output'"
+ // also has a conflicts_with_all(Vec<&str>)
+ )
+ // NOTE: In order to compile this example, comment out conflicts_with()
+ // and requires() because we have not defined an "output" or "config"
+ // argument.
+ .get_matches();
+
+ // We can find out whether or not "input" was used
+ if matches.is_present("input") {
+ println!("An input file was specified");
+ }
+
+ // We can also get the value for "input"
+ //
+ // NOTE: If we specified multiple(), this will only return the _FIRST_
+ // occurrence
+ if let Some(in_file) = matches.value_of("input") {
+ println!("An input file: {}", in_file);
+ }
+
+ // If we specified the multiple() setting we can get all the values
+ if let Some(in_v) = matches.values_of("input") {
+ for in_file in in_v {
+ println!("An input file: {}", in_file);
+ }
+ }
+
+ // We can see how many times the option was used with the occurrences_of() method
+ //
+ // NOTE: Just like with flags, if we did not specify the multiple() setting this will only
+ // return 1 no matter how many times the argument was used (unless it wasn't used at all, in
+ // in which case 0 is returned)
+ println!("The \"input\" argument was used {} times", matches.occurrences_of("input"));
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/08_subcommands.rs b/clap/examples/08_subcommands.rs
new file mode 100644
index 0000000..73bd098
--- /dev/null
+++ b/clap/examples/08_subcommands.rs
@@ -0,0 +1,57 @@
+extern crate clap;
+
+use clap::{App, Arg, SubCommand};
+
+fn main() {
+
+ // SubCommands function exactly like sub-Apps, because that's exactly what they are. Each
+ // instance of a SubCommand can have it's own version, author(s), Args, and even it's own
+ // subcommands.
+ //
+ // # Help and Version
+ // Just like Apps, each subcommand will get it's own "help" and "version" flags automatically
+ // generated. Also, like Apps, you can override "-V" or "-h" safely and still get "--help" and
+ // "--version" auto generated.
+ //
+ // NOTE: If you specify a subcommand for your App, clap will also autogenerate a "help"
+ // subcommand along with "-h" and "--help" (applies to sub-subcommands as well).
+ //
+ // Just like arg() and args(), subcommands can be specified one at a time via subcommand() or
+ // multiple ones at once with a Vec<SubCommand> provided to subcommands().
+ let matches = App::new("MyApp")
+ // Normal App and Arg configuration goes here...
+
+ // In the following example assume we wanted an application which
+ // supported an "add" subcommand, this "add" subcommand also took
+ // one positional argument of a file to add:
+ .subcommand(SubCommand::with_name("add") // The name we call argument with
+ .about("Adds files to myapp") // The message displayed in "myapp -h"
+ // or "myapp help"
+ .version("0.1") // Subcommands can have independent version
+ .author("Kevin K.") // And authors
+ .arg(Arg::with_name("input") // And their own arguments
+ .help("the file to add")
+ .index(1)
+ .required(true)))
+ .get_matches();
+
+ // You can check if a subcommand was used like normal
+ if matches.is_present("add") {
+ println!("'myapp add' was run.");
+ }
+
+ // You can get the independent subcommand matches (which function exactly like App matches)
+ if let Some(matches) = matches.subcommand_matches("add") {
+ // Safe to use unwrap() because of the required() option
+ println!("Adding file: {}", matches.value_of("input").unwrap());
+ }
+
+ // You can also match on a subcommand's name
+ match matches.subcommand_name() {
+ Some("add") => println!("'myapp add' was used"),
+ None => println!("No subcommand was used"),
+ _ => println!("Some other subcommand was used"),
+ }
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/09_auto_version.rs b/clap/examples/09_auto_version.rs
new file mode 100644
index 0000000..dfd221f
--- /dev/null
+++ b/clap/examples/09_auto_version.rs
@@ -0,0 +1,29 @@
+#[macro_use]
+extern crate clap;
+
+use clap::App;
+
+fn main() {
+ // You can have clap pull the application version directly from your Cargo.toml starting with
+ // clap v0.4.14 on crates.io (or master#a81f915 on github). Using Rust's env! macro like this:
+ //
+ // let version = format!("{}.{}.{}{}",
+ // env!("CARGO_PKG_VERSION_MAJOR"),
+ // env!("CARGO_PKG_VERSION_MINOR"),
+ // env!("CARGO_PKG_VERSION_PATCH"),
+ // option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
+ //
+ // Starting from v0.6.6 on crates.io you can also use the crate_version!() macro instead of
+ // manually using the env!() macros. Under the hood, the macro uses this exact method to get
+ // the version.
+ //
+ // Thanks to https://github.com/jhelwig for pointing this out
+ App::new("myapp")
+ .about("does awesome things")
+ // use crate_version! to pull the version number
+ .version(crate_version!())
+ .get_matches();
+
+ // running this app with the -V or --version will display whatever version is in your
+ // Cargo.toml, the default being: myapp 0.0.1
+}
diff --git a/clap/examples/10_default_values.rs b/clap/examples/10_default_values.rs
new file mode 100644
index 0000000..ca50981
--- /dev/null
+++ b/clap/examples/10_default_values.rs
@@ -0,0 +1,40 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+fn main() {
+ // There are two ways in which to get a default value, one is to use claps Arg::default_value
+ // method, and the other is to use Rust's built in Option::unwrap_or method.
+ //
+ // I'll demo both here.
+ //
+ // First, we'll use clap's Arg::default_value with an "INPUT" file.
+ let matches = App::new("myapp").about("does awesome things")
+ .arg(Arg::with_name("INPUT")
+ .help("The input file to use") // Note, we don't need to specify
+ // anything like, "Defaults to..."
+ // because clap will automatically
+ // generate that for us, and place
+ // it in the help text
+ .default_value("input.txt")
+ .index(1))
+
+ // Next we'll use the Option::unwrap_or method on this "CONFIG" option
+ .arg(Arg::with_name("CONFIG")
+ // Note that we have to manually include some verbiage to the user
+ // telling them what the default will be.
+ .help("The config file to use (default is \"config.json\")")
+ .short("c")
+ .takes_value(true))
+ .get_matches();
+
+ // It's safe to call unwrap because the value with either be what the user input at runtime
+ // or "input.txt"
+ let input = matches.value_of("INPUT").unwrap();
+
+ // Using Option::unwrap_or we get the same affect, but without the added help text injection
+ let config_file = matches.value_of("CONFIG").unwrap_or("config.json");
+
+ println!("The input file is: {}", input);
+ println!("The config file is: {}", config_file);
+}
diff --git a/clap/examples/11_only_specific_values.rs b/clap/examples/11_only_specific_values.rs
new file mode 100644
index 0000000..3445218
--- /dev/null
+++ b/clap/examples/11_only_specific_values.rs
@@ -0,0 +1,33 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+fn main() {
+ // If you have arguments of specific values you want to test for, you can use the
+ // .possible_values() method of Arg
+ //
+ // This allows you specify the valid values for that argument. If the user does not use one of
+ // those specific values, they will receive a graceful exit with error message informing them
+ // of the mistake, and what the possible valid values are
+ //
+ // For this example, assume you want one positional argument of either "fast" or "slow"
+ // i.e. the only possible ways to run the program are "myprog fast" or "myprog slow"
+ let matches = App::new("myapp").about("does awesome things")
+ .arg(Arg::with_name("MODE")
+ .help("What mode to run the program in")
+ .index(1)
+ .possible_values(&["fast", "slow"])
+ .required(true))
+ .get_matches();
+
+ // Note, it's safe to call unwrap() because the arg is required
+ match matches.value_of("MODE").unwrap() {
+ "fast" => {
+ // Do fast things...
+ },
+ "slow" => {
+ // Do slow things...
+ },
+ _ => unreachable!()
+ }
+}
diff --git a/clap/examples/12_typed_values.rs b/clap/examples/12_typed_values.rs
new file mode 100644
index 0000000..3d03e4f
--- /dev/null
+++ b/clap/examples/12_typed_values.rs
@@ -0,0 +1,50 @@
+#[macro_use]
+extern crate clap;
+
+use clap::App;
+
+fn main() {
+ // You can use some convenience macros provided by clap to get typed values, so long as the
+ // type you specify implements std::str::FromStr
+ //
+ // This works for both single, and multiple values (multiple values returns a Vec<T>)
+ //
+ // There are also two ways in which to get types, those where failures cause the program to exit
+ // with an error and usage string, and those which return a Result<T,String> or Result<Vec<T>,String>
+ // respectively. Both methods support single and multiple values.
+ //
+ // The macro which returns a Result allows you decide what to do upon a failure, exit, provide a
+ // default value, etc. You have control. But it also means you have to write the code or boiler plate
+ // to handle those instances.
+ //
+ // That is why the second method exists, so you can simply get a T or Vec<T> back, or be sure the
+ // program will exit gracefully. The catch is, the second method should *only* be used on required
+ // arguments, because if the argument isn't found, it exits. Just FYI ;)
+ //
+ // The following example shows both methods.
+ //
+ // **NOTE:** to use the macros, you must include #[macro_use] just above the 'extern crate clap;'
+ // declaration in your crate root.
+ let matches = App::new("myapp")
+ // Create two arguments, a required positional which accepts multiple values
+ // and an optional '-l value'
+ .args_from_usage(
+ "<seq>... 'A sequence of whole positive numbers, i.e. 20 25 30'
+ -l [len] 'A length to use, defaults to 10 when omitted'")
+ .get_matches();
+
+ // Here we get a value of type u32 from our optional -l argument.
+ // If the value provided to len fails to parse, we default to 10
+ //
+ // Using other methods such as unwrap_or_else(|e| println!("{}",e))
+ // are possible too.
+ let len = value_t!(matches, "len", u32).unwrap_or(10);
+
+ println!("len ({}) + 2 = {}", len, len + 2);
+
+ // This code loops through all the values provided to "seq" and adds 2
+ // If seq fails to parse, the program exits, you don't have an option
+ for v in values_t!(matches, "seq", u32).unwrap_or_else(|e| e.exit()) {
+ println!("Sequence part {} + 2: {}", v, v + 2);
+ }
+}
diff --git a/clap/examples/13a_enum_values_automatic.rs b/clap/examples/13a_enum_values_automatic.rs
new file mode 100644
index 0000000..1abe5cb
--- /dev/null
+++ b/clap/examples/13a_enum_values_automatic.rs
@@ -0,0 +1,68 @@
+// You can use clap's value_t! macro with a custom enum by implementing the std::str::FromStr
+// trait which is very straight forward. There are three ways to do this, for simple enums
+// meaning those that don't require 'pub' or any '#[derive()]' directives you can use clap's
+// simple_enum! macro. For those that require 'pub' or any '#[derive()]'s you can use clap's
+// arg_enum! macro. The third way is to implement std::str::FromStr manually.
+//
+// In most circumstances using either simple_enum! or arg_enum! is fine.
+//
+// In the following example we will create two enums using macros, assign a positional argument
+// that accepts only one of those values, and use clap to parse the argument.
+
+// Add clap like normal
+#[macro_use]
+extern crate clap;
+
+use clap::{App, Arg};
+
+// Using arg_enum! is more like traditional enum declarations
+//
+// **NOTE:** Only bare variants are supported
+arg_enum!{
+ #[derive(Debug)]
+ pub enum Oof {
+ Rab,
+ Zab,
+ Xuq
+ }
+}
+
+arg_enum!{
+ #[derive(Debug)]
+ enum Foo {
+ Bar,
+ Baz,
+ Qux
+ }
+}
+
+fn main() {
+ // Create the application like normal
+ let enum_vals = ["fast", "slow"];
+ let m = App::new("myapp")
+ // Use a single positional argument that is required
+ .arg(Arg::from_usage("<foo> 'The Foo to use'")
+ .possible_values(&Foo::variants()))
+ .arg(Arg::from_usage("<speed> 'The speed to use'")
+ // You can define a list of possible values if you want the values to be
+ // displayed in the help information. Whether you use possible_values() or
+ // not, the valid values will ALWAYS be displayed on a failed parse.
+ .possible_values(&enum_vals))
+ // For the second positional, lets not use possible_values() just to show the difference
+ .arg_from_usage("<oof> 'The Oof to use'")
+ .get_matches();
+
+ let t = value_t!(m.value_of("foo"), Foo).unwrap_or_else(|e| e.exit());
+ let t2 = value_t!(m.value_of("oof"), Oof).unwrap_or_else(|e| e.exit());
+
+
+ // Now we can use our enum like normal.
+ match t {
+ Foo::Bar => println!("Found a Bar"),
+ Foo::Baz => println!("Found a Baz"),
+ Foo::Qux => println!("Found a Qux")
+ }
+
+ // Since our Oof derives Debug, we can do this:
+ println!("Oof: {:?}", t2);
+}
diff --git a/clap/examples/13b_enum_values_manual.rs b/clap/examples/13b_enum_values_manual.rs
new file mode 100644
index 0000000..81ffe5e
--- /dev/null
+++ b/clap/examples/13b_enum_values_manual.rs
@@ -0,0 +1,54 @@
+// In the following example we will create an enum with 4 values, assign a positional argument
+// that accepts only one of those values, and use clap to parse the argument.
+//
+// Start with bringing the trait into scope.
+use std::str::FromStr;
+
+// Add clap like normal
+#[macro_use]
+extern crate clap;
+
+use clap::{App, Arg};
+
+// Define your enum
+enum Vals {
+ Foo,
+ Bar,
+ Baz,
+ Qux
+}
+
+// Implement the trait
+impl FromStr for Vals {
+ type Err = &'static str;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "Foo" => Ok(Vals::Foo),
+ "Bar" => Ok(Vals::Bar),
+ "Baz" => Ok(Vals::Baz),
+ "Qux" => Ok(Vals::Qux),
+ _ => Err("no match")
+ }
+ }
+}
+
+fn main() {
+ // Create the application like normal
+ let m = App::new("myapp")
+ // Use a single positional argument that is required
+ .arg(Arg::from_usage("<type> 'The type to use'")
+ // Define the list of possible values
+ .possible_values(&["Foo", "Bar", "Baz", "Qux"]))
+ .get_matches();
+
+ let t = value_t!(m, "type", Vals).unwrap_or_else(|e| e.exit());
+
+ // Now we can use our enum like normal.
+ match t {
+ Vals::Foo => println!("Found a Foo"),
+ Vals::Bar => println!("Found a Bar"),
+ Vals::Baz => println!("Found a Baz"),
+ Vals::Qux => println!("Found a Qux")
+ }
+}
diff --git a/clap/examples/14_groups.rs b/clap/examples/14_groups.rs
new file mode 100644
index 0000000..e160464
--- /dev/null
+++ b/clap/examples/14_groups.rs
@@ -0,0 +1,87 @@
+/// `ArgGroup`s are a family of related arguments and way for you to say, "Any of these arguments".
+/// By placing arguments in a logical group, you can make easier requirement and exclusion rules
+/// instead of having to list each individually, or when you want a rule to apply "any but not all"
+/// arguments.
+///
+/// For instance, you can make an entire `ArgGroup` required, this means that one (and *only* one)
+/// argument from that group must be present. Using more than one argument from an `ArgGroup` causes
+/// a failure (graceful exit).
+///
+/// You can also do things such as name an `ArgGroup` as a confliction or requirement, meaning any
+/// of the arguments that belong to that group will cause a failure if present, or must present
+/// respectively.
+///
+/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
+/// present out of a given set. Imagine that you had multiple arguments, and you want one of them to
+/// be required, but making all of them required isn't feasible because perhaps they conflict with
+/// each other. For example, lets say that you were building an application where one could set a
+/// given version number by supplying a string with an option argument, i.e. `--set-ver v1.2.3`, you
+/// also wanted to support automatically using a previous version number and simply incrementing one
+/// of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of
+/// these arguments shouldn't be used at one time but you want to specify that *at least one* of
+/// them is used. For this, you can create a group.
+
+extern crate clap;
+
+use clap::{App, Arg, ArgGroup};
+
+fn main() {
+ // Create application like normal
+ let matches = App::new("myapp")
+ // Add the version arguments
+ .args_from_usage("--set-ver [ver] 'set version manually'
+ --major 'auto inc major'
+ --minor 'auto inc minor'
+ --patch 'auto inc patch'")
+ // Create a group, make it required, and add the above arguments
+ .group(ArgGroup::with_name("vers")
+ .required(true)
+ .args(&["ver", "major", "minor", "patch"]))
+ // Arguments can also be added to a group individually, these two arguments
+ // are part of the "input" group which is not required
+ .arg(Arg::from_usage("[INPUT_FILE] 'some regular input'")
+ .group("input"))
+ .arg(Arg::from_usage("--spec-in [SPEC_IN] 'some special input argument'")
+ .group("input"))
+ // Now let's assume we have a -c [config] argument which requires one of
+ // (but **not** both) the "input" arguments
+ .arg(Arg::with_name("config")
+ .short("c")
+ .takes_value(true)
+ .requires("input"))
+ .get_matches();
+
+ // Let's assume the old version 1.2.3
+ let mut major = 1;
+ let mut minor = 2;
+ let mut patch = 3;
+
+ // See if --set-ver was used to set the version manually
+ let version = if let Some(ver) = matches.value_of("ver") {
+ format!("{}", ver)
+ } else {
+ // Increment the one requested (in a real program, we'd reset the lower numbers)
+ let (maj, min, pat) = (matches.is_present("major"),
+ matches.is_present("minor"),
+ matches.is_present("patch"));
+ match (maj, min, pat) {
+ (true, _, _) => major += 1,
+ (_, true, _) => minor += 1,
+ (_, _, true) => patch += 1,
+ _ => unreachable!(),
+ };
+ format!("{}.{}.{}", major, minor, patch)
+ };
+
+ println!("Version: {}", version);
+
+ // Check for usage of -c
+ if matches.is_present("config") {
+ let input = matches.value_of("INPUT_FILE").unwrap_or(matches.value_of("SPEC_IN").unwrap());
+ println!("Doing work using input {} and config {}",
+ input,
+ matches.value_of("config").unwrap());
+ }
+
+
+}
diff --git a/clap/examples/15_custom_validator.rs b/clap/examples/15_custom_validator.rs
new file mode 100644
index 0000000..a5c0d42
--- /dev/null
+++ b/clap/examples/15_custom_validator.rs
@@ -0,0 +1,37 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+fn main() {
+ // You can define a function (or a closure) to use as a validator to argument values. The
+ // function must accept a String and return Result<(), String> where Err(String) is the message
+ // displayed to the user.
+
+ let matches = App::new("myapp")
+ // Application logic goes here...
+ .arg(Arg::with_name("input")
+ .help("the input file to use")
+ .index(1)
+ .required(true)
+ // You can pass in a closure, or a function
+ .validator(is_png))
+ .get_matches();
+
+ // Here we can call .unwrap() because the argument is required.
+ println!("The .PNG file is: {}", matches.value_of("input").unwrap());
+}
+
+fn is_png(val: String) -> Result<(), String> {
+ // val is the argument value passed in by the user
+ // val has type of String.
+ if val.ends_with(".png") {
+ Ok(())
+ } else {
+ // clap automatically adds "error: " to the beginning
+ // of the message.
+ Err(String::from("the file format must be png."))
+ }
+ // Of course, you can do more complicated validation as
+ // well, but for the simplicity, this example only checks
+ // if the value passed in ends with ".png" or not.
+}
diff --git a/clap/examples/16_app_settings.rs b/clap/examples/16_app_settings.rs
new file mode 100644
index 0000000..ab1d185
--- /dev/null
+++ b/clap/examples/16_app_settings.rs
@@ -0,0 +1,41 @@
+extern crate clap;
+
+use clap::{App, AppSettings, SubCommand};
+
+fn main() {
+ // You can use AppSettings to change the application level behavior of clap. .setting() function
+ // of App struct takes AppSettings enum as argument. There is also .settings() function which
+ // takes slice of AppSettings enum. You can learn more about AppSettings in the documentation,
+ // which also has examples on each setting.
+ //
+ // This example will only show usage of one AppSettings setting. See documentation for more
+ // information.
+
+ let matches = App::new("myapp")
+ .setting(AppSettings::SubcommandsNegateReqs)
+ // Negates requirement of parent command.
+
+ .arg_from_usage("<input> 'input file to use'")
+ // Required positional argument called input. This
+ // will be only required if subcommand is not present.
+
+ .subcommand(SubCommand::with_name("test")
+ .about("does some testing"))
+ // if program is invoked with subcommand, you do not
+ // need to specify the <input> argument anymore due to
+ // the AppSettings::SubcommandsNegateReqs setting.
+
+ .get_matches();
+
+ // Calling unwrap() on "input" would not be advised here, because although it's required,
+ // if the user uses a subcommand, those requirements are no longer required. Hence, we should
+ // use some sort of 'if let' construct
+ if let Some(inp) = matches.value_of("input") {
+ println!("The input file is: {}", inp);
+ }
+
+ match matches.subcommand() {
+ ("test", _) => println!("The 'test' subcommand was used"),
+ _ => unreachable!()
+ }
+}
diff --git a/clap/examples/17_yaml.rs b/clap/examples/17_yaml.rs
new file mode 100644
index 0000000..3353d73
--- /dev/null
+++ b/clap/examples/17_yaml.rs
@@ -0,0 +1,53 @@
+// In order to use YAML to define your CLI you must compile clap with the "yaml" feature because
+// it's **not** included by default.
+//
+// In order to do this, ensure your Cargo.toml looks like one of the following:
+//
+// [dependencies.clap]
+// features = ["yaml"]
+//
+// __OR__
+//
+// [dependencies]
+// clap = { features = ["yaml"] }
+
+
+// Using yaml requires calling a clap macro `load_yaml!()` so we must use the '#[macro_use]'
+// directive
+#[macro_use]
+extern crate clap;
+
+#[cfg(feature = "yaml")]
+fn main() {
+ use clap::App;
+
+ // To load a yaml file containing our CLI definition such as the example '17_yaml.yml' we can
+ // use the convenience macro which loads the file at compile relative to the current file
+ // similar to how modules are found.
+ //
+ // Then we pass that yaml object to App to build the CLI.
+ //
+ // Finally we call get_matches() to start the parsing process. We use the matches just as we
+ // normally would
+ let yml = load_yaml!("17_yaml.yml");
+ let m = App::from_yaml(yml).get_matches();
+
+ // Because the example 17_yaml.yml is rather large we'll just look a single arg so you can
+ // see that it works...
+ if let Some(mode) = m.value_of("mode") {
+ match mode {
+ "vi" => println!("You are using vi"),
+ "emacs" => println!("You are using emacs..."),
+ _ => unreachable!()
+ }
+ } else {
+ println!("--mode <MODE> wasn't used...");
+ }
+}
+
+#[cfg(not(feature = "yaml"))]
+fn main() {
+ // As stated above, if clap is not compiled with the YAML feature, it is disabled.
+ println!("YAML feature is disabled.");
+ println!("Pass --features yaml to cargo when trying this example.");
+}
diff --git a/clap/examples/17_yaml.yml b/clap/examples/17_yaml.yml
new file mode 100644
index 0000000..b0d58b3
--- /dev/null
+++ b/clap/examples/17_yaml.yml
@@ -0,0 +1,97 @@
+name: yml_app
+version: "1.0"
+about: an example using a .yml file to build a CLI
+author: Kevin K. <kbknapp@gmail.com>
+
+# AppSettings can be defined as a list and are **not** ascii case sensitive
+settings:
+ - ArgRequiredElseHelp
+
+# All Args must be defined in the 'args:' list where the name of the arg, is the
+# key to a Hash object
+args:
+ # The name of this argument, is 'opt' which will be used to access the value
+ # later in your Rust code
+ - opt:
+ help: example option argument from yaml
+ short: o
+ long: option
+ multiple: true
+ takes_value: true
+ - pos:
+ help: example positional argument from yaml
+ index: 1
+ # A list of possible values can be defined as a list
+ possible_values:
+ - fast
+ - slow
+ - flag:
+ help: demo flag argument
+ short: F
+ multiple: true
+ global: true
+ # Conflicts, mutual overrides, and requirements can all be defined as a
+ # list, where the key is the name of the other argument
+ conflicts_with:
+ - opt
+ requires:
+ - pos
+ - mode:
+ long: mode
+ help: shows an option with specific values
+ # possible_values can also be defined in this list format
+ possible_values: [ vi, emacs ]
+ takes_value: true
+ - mvals:
+ long: mult-vals
+ help: demos an option which has two named values
+ # value names can be described in a list, where the help will be shown
+ # --mult-vals <one> <two>
+ value_names:
+ - one
+ - two
+ - minvals:
+ long: min-vals
+ multiple: true
+ help: you must supply at least two values to satisfy me
+ min_values: 2
+ - maxvals:
+ long: max-vals
+ multiple: true
+ help: you can only supply a max of 3 values for me!
+ max_values: 3
+
+# All subcommands must be listed in the 'subcommand:' object, where the key to
+# the list is the name of the subcommand, and all settings for that command are
+# are part of a Hash object
+subcommands:
+ # The name of this subcommand will be 'subcmd' which can be accessed in your
+ # Rust code later
+ - subcmd:
+ about: demos subcommands from yaml
+ version: "0.1"
+ author: Kevin K. <kbknapp@gmail.com>
+ # Subcommand args are exactly like App args
+ args:
+ - scopt:
+ short: B
+ multiple: true
+ help: example subcommand option
+ takes_value: true
+ - scpos1:
+ help: example subcommand positional
+ index: 1
+
+# ArgGroups are supported as well, and must be sepcified in the 'groups:'
+# object of this file
+groups:
+ # the name of the ArgGoup is specified here
+ - min-max-vals:
+ # All args and groups that are a part of this group are set here
+ args:
+ - minvals
+ - maxvals
+ # setting conflicts is done the same manner as setting 'args:'
+ #
+ # to make this group required, you could set 'required: true' but for
+ # this example we won't do that.
diff --git a/clap/examples/18_builder_macro.rs b/clap/examples/18_builder_macro.rs
new file mode 100644
index 0000000..6bdce47
--- /dev/null
+++ b/clap/examples/18_builder_macro.rs
@@ -0,0 +1,84 @@
+#[macro_use]
+extern crate clap;
+
+// Note, there isn't a need for "use clap::{ ... };" Because the clap_app! macro uses
+// $crate:: internally
+
+fn main() {
+
+ // Validation example testing that a file exists
+ let file_exists = |path| {
+ if std::fs::metadata(path).is_ok() {
+ Ok(())
+ } else {
+ Err(String::from("File doesn't exist"))
+ }
+ };
+
+ // External module may contain this subcommand. If this exists in another module, a function is
+ // required to access it. Recommend `fn clap() -> Clap::SubCommand`.
+ let external_sub_command = clap_app!( @subcommand foo =>
+ (@arg bar: -b "Bar")
+ );
+
+ let matches = clap_app!(MyApp =>
+ (@setting SubcommandRequiredElseHelp)
+ (version: "1.0")
+ (author: "Alice")
+ (about: "Does awesome things")
+ (@arg config: -c --config <conf> #{1, 2} {file_exists} "Sets a custom config file")
+ (@arg proxyHostname: --("proxy-hostname") +takes_value "Sets the hostname of the proxy to use")
+ (@arg input: * "Input file")
+ (@group test =>
+ (@attributes +required)
+ (@arg output: "Sets an optional output file")
+ (@arg debug: -d ... "Turn debugging information on")
+ )
+ (subcommand: external_sub_command)
+ (@subcommand test =>
+ (about: "does testing things")
+ (version: "2.5")
+ (@arg list: -l "Lists test values")
+ (@arg test_req: -r requires[list] "Tests requirement for listing")
+ (@arg aaaa: --aaaa +takes_value {
+ |a| if a.contains('a') {
+ Ok(())
+ } else {
+ Err(String::from("string does not contain at least one a"))
+ }
+ } "Test if the argument contains an a")
+ )
+ ).get_matches();
+
+ // You can check the value provided by positional arguments, or option arguments
+ if let Some(o) = matches.value_of("output") {
+ println!("Value for output: {}", o);
+ }
+
+ if let Some(c) = matches.value_of("config") {
+ println!("Value for config: {}", c);
+ }
+
+ // You can see how many times a particular flag or argument occurred
+ // Note, only flags can have multiple occurrences
+ match matches.occurrences_of("debug") {
+ 0 => println!("Debug mode is off"),
+ 1 => println!("Debug mode is kind of on"),
+ 2 => println!("Debug mode is on"),
+ 3 | _ => println!("Don't be crazy"),
+ }
+
+ // You can check for the existence of subcommands, and if found use their
+ // matches just as you would the top level app
+ if let Some(matches) = matches.subcommand_matches("test") {
+ // "$ myapp test" was run
+ if matches.is_present("list") {
+ // "$ myapp test -l" was run
+ println!("Printing testing lists...");
+ } else {
+ println!("Not printing testing lists...");
+ }
+ }
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/19_auto_authors.rs b/clap/examples/19_auto_authors.rs
new file mode 100644
index 0000000..afbb985
--- /dev/null
+++ b/clap/examples/19_auto_authors.rs
@@ -0,0 +1,15 @@
+#[macro_use]
+extern crate clap;
+
+use clap::App;
+
+fn main() {
+ App::new("myapp")
+ .about("does awesome things")
+ // use crate_authors! to pull the author(s) names from the Cargo.toml
+ .author(crate_authors!())
+ .get_matches();
+
+ // running this app with -h will display whatever author(s) are in your
+ // Cargo.toml
+}
diff --git a/clap/examples/20_subcommands.rs b/clap/examples/20_subcommands.rs
new file mode 100644
index 0000000..f80f46d
--- /dev/null
+++ b/clap/examples/20_subcommands.rs
@@ -0,0 +1,143 @@
+// Working with subcommands is simple. There are a few key points to remember when working with
+// subcommands in clap. First, SubCommands are really just Apps. This means they can have their own
+// settings, version, authors, args, and even their own subcommands. The next thing to remember is
+// that subcommands are set up in a tree like hierarchy.
+//
+// An ASCII art depiction may help explain this better. Using a fictional version of git as the demo
+// subject. Imagine the following are all subcommands of git (note, the author is aware these aren't
+// actually all subcommands in the real git interface, but it makes explanation easier)
+//
+// Top Level App (git) TOP
+// |
+// -----------------------------------------
+// / | \ \
+// clone push add commit LEVEL 1
+// | / \ / \ |
+// url origin remote ref name message LEVEL 2
+// / /\
+// path remote local LEVEL 3
+//
+// Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all inclusive
+// list):
+//
+// $ git clone url
+// $ git push origin path
+// $ git add ref local
+// $ git commit message
+//
+// Notice only one command per "level" may be used. You could not, for example, do:
+//
+// $ git clone url push origin path
+//
+// It's also important to know that subcommands each have their own set of matches and may have args
+// with the same name as other subcommands in a different part of the tree hierarchy (i.e. the arg
+// names aren't in a flat namespace).
+//
+// In order to use subcommands in clap, you only need to know which subcommand you're at in your
+// tree, and which args are defined on that subcommand.
+//
+// Let's make a quick program to illustrate. We'll be using the same example as above but for
+// brevity sake we won't implement all of the subcommands, only a few.
+
+extern crate clap;
+
+use clap::{App, Arg, SubCommand, AppSettings};
+
+fn main() {
+
+ let matches = App::new("git")
+ .about("A fictional versioning CLI")
+ .version("1.0")
+ .author("Me")
+ .subcommand(SubCommand::with_name("clone")
+ .about("clones repos")
+ .arg(Arg::with_name("repo")
+ .help("The repo to clone")
+ .required(true)))
+ .subcommand(SubCommand::with_name("push")
+ .about("pushes things")
+ .setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(SubCommand::with_name("remote") // Subcommands can have their own subcommands,
+ // which in turn have their own subcommands
+ .about("pushes remote things")
+ .arg(Arg::with_name("repo")
+ .required(true)
+ .help("The remote repo to push things to")))
+ .subcommand(SubCommand::with_name("local")
+ .about("pushes local things")))
+ .subcommand(SubCommand::with_name("add")
+ .about("adds things")
+ .author("Someone Else") // Subcommands can list different authors
+ .version("v2.0 (I'm versioned differently") // or different version from their parents
+ .setting(AppSettings::ArgRequiredElseHelp) // They can even have different settings
+ .arg(Arg::with_name("stuff")
+ .long("stuff")
+ .help("Stuff to add")
+ .takes_value(true)
+ .multiple(true)))
+ .get_matches();
+
+ // At this point, the matches we have point to git. Keep this in mind...
+
+ // You can check if one of git's subcommands was used
+ if matches.is_present("clone") {
+ println!("'git clone' was run.");
+ }
+
+ // You can see which subcommand was used
+ if let Some(subcommand) = matches.subcommand_name() {
+ println!("'git {}' was used", subcommand);
+
+ // It's important to note, this *only* check's git's DIRECT children, **NOT** it's
+ // grandchildren, great grandchildren, etc.
+ //
+ // i.e. if the command `git push remove --stuff foo` was run, the above will only print out,
+ // `git push` was used. We'd need to get push's matches to see further into the tree
+ }
+
+ // An alternative to checking the name is matching on known names. Again notice that only the
+ // direct children are matched here.
+ match matches.subcommand_name() {
+ Some("clone") => println!("'git clone' was used"),
+ Some("push") => println!("'git push' was used"),
+ Some("add") => println!("'git add' was used"),
+ None => println!("No subcommand was used"),
+ _ => unreachable!(), // Assuming you've listed all direct children above, this is unreachable
+ }
+
+ // You could get the independent subcommand matches, although this is less common
+ if let Some(clone_matches) = matches.subcommand_matches("clone") {
+ // Now we have a reference to clone's matches
+ println!("Cloning repo: {}", clone_matches.value_of("repo").unwrap());
+ }
+
+ // The most common way to handle subcommands is via a combined approach using
+ // `ArgMatches::subcommand` which returns a tuple of both the name and matches
+ match matches.subcommand() {
+ ("clone", Some(clone_matches)) =>{
+ // Now we have a reference to clone's matches
+ println!("Cloning {}", clone_matches.value_of("repo").unwrap());
+ },
+ ("push", Some(push_matches)) =>{
+ // Now we have a reference to push's matches
+ match push_matches.subcommand() {
+ ("remote", Some(remote_matches)) =>{
+ // Now we have a reference to remote's matches
+ println!("Pushing to {}", remote_matches.value_of("repo").unwrap());
+ },
+ ("local", Some(_)) =>{
+ println!("'git push local' was used");
+ },
+ _ => unreachable!(),
+ }
+ },
+ ("add", Some(add_matches)) =>{
+ // Now we have a reference to add's matches
+ println!("Adding {}", add_matches.values_of("stuff").unwrap().collect::<Vec<_>>().join(", "));
+ },
+ ("", None) => println!("No subcommand was used"), // If no subcommand was used it'll match the tuple ("", None)
+ _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!()
+ }
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/21_aliases.rs b/clap/examples/21_aliases.rs
new file mode 100644
index 0000000..3be0445
--- /dev/null
+++ b/clap/examples/21_aliases.rs
@@ -0,0 +1,39 @@
+extern crate clap;
+
+use clap::{App, Arg, SubCommand};
+
+fn main() {
+
+ let matches = App::new("MyApp")
+ .subcommand(SubCommand::with_name("ls")
+ .aliases(&["list", "dir"])
+ .about("Adds files to myapp")
+ .version("0.1")
+ .author("Kevin K.")
+ .arg(Arg::with_name("input")
+ .help("the file to add")
+ .index(1)
+ .required(true))
+ )
+ .get_matches();
+
+ // You can check if a subcommand was used like normal
+ if matches.is_present("add") {
+ println!("'myapp add' was run.");
+ }
+
+ // You can get the independent subcommand matches (which function exactly like App matches)
+ if let Some(matches) = matches.subcommand_matches("add") {
+ // Safe to use unwrap() because of the required() option
+ println!("Adding file: {}", matches.value_of("input").unwrap());
+ }
+
+ // You can also match on a subcommand's name
+ match matches.subcommand_name() {
+ Some("add") => println!("'myapp add' was used"),
+ None => println!("No subcommand was used"),
+ _ => println!("Some other subcommand was used"),
+ }
+
+ // Continued program logic goes here...
+}
diff --git a/clap/examples/22_stop_parsing_with_--.rs b/clap/examples/22_stop_parsing_with_--.rs
new file mode 100644
index 0000000..a5ba5b3
--- /dev/null
+++ b/clap/examples/22_stop_parsing_with_--.rs
@@ -0,0 +1,25 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+/// myprog -f -p=bob -- sloppy slop slop
+fn main() {
+
+ let matches = App::new("myprog")
+ .arg(Arg::with_name("eff")
+ .short("f"))
+ .arg(Arg::with_name("pea")
+ .short("p")
+ .takes_value(true))
+ .arg(Arg::with_name("slop")
+ .multiple(true)
+ .last(true))
+ .get_matches();
+
+
+ println!("-f used: {:?}", matches.is_present("eff"));
+ println!("-p's value: {:?}", matches.value_of("pea"));
+ println!("'slops' values: {:?}", matches.values_of("slop").map(|vals| vals.collect::<Vec<_>>()));
+
+ // Continued program logic goes here...
+}
diff --git a/clap/justfile b/clap/justfile
new file mode 100644
index 0000000..0768764
--- /dev/null
+++ b/clap/justfile
@@ -0,0 +1,39 @@
+@update-contributors:
+ echo 'Removing old CONTRIBUTORS.md'
+ mv CONTRIBUTORS.md CONTRIBUTORS.md.bak
+ echo 'Downloading a list of new contributors'
+ echo "the following is a list of contributors:" > CONTRIBUTORS.md
+ echo "" >> CONTRIBUTORS.md
+ echo "" >> CONTRIBUTORS.md
+ githubcontrib --owner clap-rs --repo clap --sha master --cols 6 --format md --showlogin true --sortBy contributions --sortOrder desc >> CONTRIBUTORS.md
+ echo "" >> CONTRIBUTORS.md
+ echo "" >> CONTRIBUTORS.md
+ echo "This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list)" >> CONTRIBUTORS.md
+ rm CONTRIBUTORS.md.bak
+
+run-test TEST:
+ cargo test --test {{TEST}}
+
+debug TEST:
+ cargo test --test {{TEST}} --features debug
+
+run-tests:
+ cargo test --features "yaml unstable"
+
+@bench: nightly
+ cargo bench && just remove-nightly
+
+nightly:
+ rustup override add nightly
+
+remove-nightly:
+ rustup override remove
+
+@lint: nightly
+ cargo build --features lints && just remove-nightly
+
+clean:
+ cargo clean
+ find . -type f -name "*.orig" -exec rm {} \;
+ find . -type f -name "*.bk" -exec rm {} \;
+ find . -type f -name ".*~" -exec rm {} \;
diff --git a/clap/rustfmt.toml b/clap/rustfmt.toml
new file mode 100644
index 0000000..0136d86
--- /dev/null
+++ b/clap/rustfmt.toml
@@ -0,0 +1,4 @@
+format_strings = false
+chain_overflow_last = false
+same_line_if_else = true
+fn_single_line = true
diff --git a/clap/src/app/help.rs b/clap/src/app/help.rs
new file mode 100644
index 0000000..34f97ac
--- /dev/null
+++ b/clap/src/app/help.rs
@@ -0,0 +1,1028 @@
+// Std
+use std::borrow::Cow;
+use std::cmp;
+use std::collections::BTreeMap;
+use std::fmt::Display;
+use std::io::{self, Cursor, Read, Write};
+use std::usize;
+
+// Internal
+use app::parser::Parser;
+use app::usage;
+use app::{App, AppSettings};
+use args::{AnyArg, ArgSettings, DispOrder};
+use errors::{Error, Result as ClapResult};
+use fmt::{Colorizer, ColorizerOption, Format};
+use map::VecMap;
+use INTERNAL_ERROR_MSG;
+
+// Third Party
+#[cfg(feature = "wrap_help")]
+use term_size;
+use textwrap;
+use unicode_width::UnicodeWidthStr;
+
+#[cfg(not(feature = "wrap_help"))]
+mod term_size {
+ pub fn dimensions() -> Option<(usize, usize)> {
+ None
+ }
+}
+
+fn str_width(s: &str) -> usize {
+ UnicodeWidthStr::width(s)
+}
+
+const TAB: &'static str = " ";
+
+// These are just convenient traits to make the code easier to read.
+trait ArgWithDisplay<'b, 'c>: AnyArg<'b, 'c> + Display {}
+impl<'b, 'c, T> ArgWithDisplay<'b, 'c> for T
+where
+ T: AnyArg<'b, 'c> + Display,
+{
+}
+
+trait ArgWithOrder<'b, 'c>: ArgWithDisplay<'b, 'c> + DispOrder {
+ fn as_base(&self) -> &ArgWithDisplay<'b, 'c>;
+}
+impl<'b, 'c, T> ArgWithOrder<'b, 'c> for T
+where
+ T: ArgWithDisplay<'b, 'c> + DispOrder,
+{
+ fn as_base(&self) -> &ArgWithDisplay<'b, 'c> {
+ self
+ }
+}
+
+fn as_arg_trait<'a, 'b, T: ArgWithOrder<'a, 'b>>(x: &T) -> &ArgWithOrder<'a, 'b> {
+ x
+}
+
+impl<'b, 'c> DispOrder for App<'b, 'c> {
+ fn disp_ord(&self) -> usize {
+ 999
+ }
+}
+
+macro_rules! color {
+ ($_self:ident, $s:expr, $c:ident) => {
+ if $_self.color {
+ write!($_self.writer, "{}", $_self.cizer.$c($s))
+ } else {
+ write!($_self.writer, "{}", $s)
+ }
+ };
+ ($_self:ident, $fmt_s:expr, $v:expr, $c:ident) => {
+ if $_self.color {
+ write!($_self.writer, "{}", $_self.cizer.$c(format!($fmt_s, $v)))
+ } else {
+ write!($_self.writer, $fmt_s, $v)
+ }
+ };
+}
+
+/// `clap` Help Writer.
+///
+/// Wraps a writer stream providing different methods to generate help for `clap` objects.
+pub struct Help<'a> {
+ writer: &'a mut Write,
+ next_line_help: bool,
+ hide_pv: bool,
+ term_w: usize,
+ color: bool,
+ cizer: Colorizer,
+ longest: usize,
+ force_next_line: bool,
+ use_long: bool,
+}
+
+// Public Functions
+impl<'a> Help<'a> {
+ /// Create a new `Help` instance.
+ #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
+ pub fn new(
+ w: &'a mut Write,
+ next_line_help: bool,
+ hide_pv: bool,
+ color: bool,
+ cizer: Colorizer,
+ term_w: Option<usize>,
+ max_w: Option<usize>,
+ use_long: bool,
+ ) -> Self {
+ debugln!("Help::new;");
+ Help {
+ writer: w,
+ next_line_help: next_line_help,
+ hide_pv: hide_pv,
+ term_w: match term_w {
+ Some(width) => if width == 0 {
+ usize::MAX
+ } else {
+ width
+ },
+ None => cmp::min(
+ term_size::dimensions().map_or(120, |(w, _)| w),
+ match max_w {
+ None | Some(0) => usize::MAX,
+ Some(mw) => mw,
+ },
+ ),
+ },
+ color: color,
+ cizer: cizer,
+ longest: 0,
+ force_next_line: false,
+ use_long: use_long,
+ }
+ }
+
+ /// Reads help settings from an App
+ /// and write its help to the wrapped stream.
+ pub fn write_app_help(w: &'a mut Write, app: &App, use_long: bool) -> ClapResult<()> {
+ debugln!("Help::write_app_help;");
+ Self::write_parser_help(w, &app.p, use_long)
+ }
+
+ /// Reads help settings from a Parser
+ /// and write its help to the wrapped stream.
+ pub fn write_parser_help(w: &'a mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> {
+ debugln!("Help::write_parser_help;");
+ Self::_write_parser_help(w, parser, false, use_long)
+ }
+
+ /// Reads help settings from a Parser
+ /// and write its help to the wrapped stream which will be stderr. This method prevents
+ /// formatting when required.
+ pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
+ debugln!("Help::write_parser_help;");
+ Self::_write_parser_help(w, parser, true, false)
+ }
+
+ #[doc(hidden)]
+ pub fn _write_parser_help(
+ w: &'a mut Write,
+ parser: &Parser,
+ stderr: bool,
+ use_long: bool,
+ ) -> ClapResult<()> {
+ debugln!("Help::write_parser_help;");
+ let nlh = parser.is_set(AppSettings::NextLineHelp);
+ let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
+ let color = parser.is_set(AppSettings::ColoredHelp);
+ let cizer = Colorizer::new(ColorizerOption {
+ use_stderr: stderr,
+ when: parser.color(),
+ });
+ Self::new(
+ w,
+ nlh,
+ hide_v,
+ color,
+ cizer,
+ parser.meta.term_w,
+ parser.meta.max_w,
+ use_long,
+ ).write_help(parser)
+ }
+
+ /// Writes the parser help to the wrapped stream.
+ pub fn write_help(&mut self, parser: &Parser) -> ClapResult<()> {
+ debugln!("Help::write_help;");
+ if let Some(h) = parser.meta.help_str {
+ write!(self.writer, "{}", h).map_err(Error::from)?;
+ } else if let Some(tmpl) = parser.meta.template {
+ self.write_templated_help(parser, tmpl)?;
+ } else {
+ self.write_default_help(parser)?;
+ }
+ Ok(())
+ }
+}
+
+// Methods to write AnyArg help.
+impl<'a> Help<'a> {
+ /// Writes help for each argument in the order they were declared to the wrapped stream.
+ fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
+ where
+ I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>,
+ {
+ debugln!("Help::write_args_unsorted;");
+ // The shortest an arg can legally be is 2 (i.e. '-x')
+ self.longest = 2;
+ let mut arg_v = Vec::with_capacity(10);
+ let use_long = self.use_long;
+ for arg in args.filter(|arg| should_show_arg(use_long, *arg)) {
+ if arg.longest_filter() {
+ self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
+ }
+ arg_v.push(arg)
+ }
+ let mut first = true;
+ for arg in arg_v {
+ if first {
+ first = false;
+ } else {
+ self.writer.write_all(b"\n")?;
+ }
+ self.write_arg(arg.as_base())?;
+ }
+ Ok(())
+ }
+
+ /// Sorts arguments by length and display order and write their help to the wrapped stream.
+ fn write_args<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
+ where
+ I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>,
+ {
+ debugln!("Help::write_args;");
+ // The shortest an arg can legally be is 2 (i.e. '-x')
+ self.longest = 2;
+ let mut ord_m = VecMap::new();
+ let use_long = self.use_long;
+ // Determine the longest
+ for arg in args.filter(|arg| {
+ // If it's NextLineHelp, but we don't care to compute how long because it may be
+ // NextLineHelp on purpose *because* it's so long and would throw off all other
+ // args alignment
+ should_show_arg(use_long, *arg)
+ }) {
+ if arg.longest_filter() {
+ debugln!("Help::write_args: Current Longest...{}", self.longest);
+ self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
+ debugln!("Help::write_args: New Longest...{}", self.longest);
+ }
+ let btm = ord_m.entry(arg.disp_ord()).or_insert(BTreeMap::new());
+ btm.insert(arg.name(), arg);
+ }
+ let mut first = true;
+ for btm in ord_m.values() {
+ for arg in btm.values() {
+ if first {
+ first = false;
+ } else {
+ self.writer.write_all(b"\n")?;
+ }
+ self.write_arg(arg.as_base())?;
+ }
+ }
+ Ok(())
+ }
+
+ /// Writes help for an argument to the wrapped stream.
+ fn write_arg<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> {
+ debugln!("Help::write_arg;");
+ self.short(arg)?;
+ self.long(arg)?;
+ let spec_vals = self.val(arg)?;
+ self.help(arg, &*spec_vals)?;
+ Ok(())
+ }
+
+ /// Writes argument's short command to the wrapped stream.
+ fn short<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> {
+ debugln!("Help::short;");
+ write!(self.writer, "{}", TAB)?;
+ if let Some(s) = arg.short() {
+ color!(self, "-{}", s, good)
+ } else if arg.has_switch() {
+ write!(self.writer, "{}", TAB)
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Writes argument's long command to the wrapped stream.
+ fn long<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> {
+ debugln!("Help::long;");
+ if !arg.has_switch() {
+ return Ok(());
+ }
+ if arg.takes_value() {
+ if let Some(l) = arg.long() {
+ if arg.short().is_some() {
+ write!(self.writer, ", ")?;
+ }
+ color!(self, "--{}", l, good)?
+ }
+
+ let sep = if arg.is_set(ArgSettings::RequireEquals) {
+ "="
+ } else {
+ " "
+ };
+ write!(self.writer, "{}", sep)?;
+ } else if let Some(l) = arg.long() {
+ if arg.short().is_some() {
+ write!(self.writer, ", ")?;
+ }
+ color!(self, "--{}", l, good)?;
+ }
+ Ok(())
+ }
+
+ /// Writes argument's possible values to the wrapped stream.
+ fn val<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> Result<String, io::Error> {
+ debugln!("Help::val: arg={}", arg);
+ if arg.takes_value() {
+ let delim = if arg.is_set(ArgSettings::RequireDelimiter) {
+ arg.val_delim().expect(INTERNAL_ERROR_MSG)
+ } else {
+ ' '
+ };
+ if let Some(vec) = arg.val_names() {
+ let mut it = vec.iter().peekable();
+ while let Some((_, val)) = it.next() {
+ color!(self, "<{}>", val, good)?;
+ if it.peek().is_some() {
+ write!(self.writer, "{}", delim)?;
+ }
+ }
+ let num = vec.len();
+ if arg.is_set(ArgSettings::Multiple) && num == 1 {
+ color!(self, "...", good)?;
+ }
+ } else if let Some(num) = arg.num_vals() {
+ let mut it = (0..num).peekable();
+ while let Some(_) = it.next() {
+ color!(self, "<{}>", arg.name(), good)?;
+ if it.peek().is_some() {
+ write!(self.writer, "{}", delim)?;
+ }
+ }
+ if arg.is_set(ArgSettings::Multiple) && num == 1 {
+ color!(self, "...", good)?;
+ }
+ } else if arg.has_switch() {
+ color!(self, "<{}>", arg.name(), good)?;
+ if arg.is_set(ArgSettings::Multiple) {
+ color!(self, "...", good)?;
+ }
+ } else {
+ color!(self, "{}", arg, good)?;
+ }
+ }
+
+ let spec_vals = self.spec_vals(arg);
+ let h = arg.help().unwrap_or("");
+ let h_w = str_width(h) + str_width(&*spec_vals);
+ let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
+ let taken = self.longest + 12;
+ self.force_next_line = !nlh && self.term_w >= taken
+ && (taken as f32 / self.term_w as f32) > 0.40
+ && h_w > (self.term_w - taken);
+
+ debug!("Help::val: Has switch...");
+ if arg.has_switch() {
+ sdebugln!("Yes");
+ debugln!("Help::val: force_next_line...{:?}", self.force_next_line);
+ debugln!("Help::val: nlh...{:?}", nlh);
+ debugln!("Help::val: taken...{}", taken);
+ debugln!(
+ "Help::val: help_width > (width - taken)...{} > ({} - {})",
+ h_w,
+ self.term_w,
+ taken
+ );
+ debugln!("Help::val: longest...{}", self.longest);
+ debug!("Help::val: next_line...");
+ if !(nlh || self.force_next_line) {
+ sdebugln!("No");
+ let self_len = str_width(arg.to_string().as_str());
+ // subtract ourself
+ let mut spcs = self.longest - self_len;
+ // Since we're writing spaces from the tab point we first need to know if we
+ // had a long and short, or just short
+ if arg.long().is_some() {
+ // Only account 4 after the val
+ spcs += 4;
+ } else {
+ // Only account for ', --' + 4 after the val
+ spcs += 8;
+ }
+
+ write_nspaces!(self.writer, spcs);
+ } else {
+ sdebugln!("Yes");
+ }
+ } else if !(nlh || self.force_next_line) {
+ sdebugln!("No, and not next_line");
+ write_nspaces!(
+ self.writer,
+ self.longest + 4 - (str_width(arg.to_string().as_str()))
+ );
+ } else {
+ sdebugln!("No");
+ }
+ Ok(spec_vals)
+ }
+
+ fn write_before_after_help(&mut self, h: &str) -> io::Result<()> {
+ debugln!("Help::write_before_after_help;");
+ let mut help = String::from(h);
+ // determine if our help fits or needs to wrap
+ debugln!(
+ "Help::write_before_after_help: Term width...{}",
+ self.term_w
+ );
+ let too_long = str_width(h) >= self.term_w;
+
+ debug!("Help::write_before_after_help: Too long...");
+ if too_long || h.contains("{n}") {
+ sdebugln!("Yes");
+ debugln!("Help::write_before_after_help: help: {}", help);
+ debugln!(
+ "Help::write_before_after_help: help width: {}",
+ str_width(&*help)
+ );
+ // Determine how many newlines we need to insert
+ debugln!(
+ "Help::write_before_after_help: Usable space: {}",
+ self.term_w
+ );
+ help = wrap_help(&help.replace("{n}", "\n"), self.term_w);
+ } else {
+ sdebugln!("No");
+ }
+ write!(self.writer, "{}", help)?;
+ Ok(())
+ }
+
+ /// Writes argument's help to the wrapped stream.
+ fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> {
+ debugln!("Help::help;");
+ let h = if self.use_long && arg.name() != "" {
+ arg.long_help().unwrap_or_else(|| arg.help().unwrap_or(""))
+ } else {
+ arg.help().unwrap_or_else(|| arg.long_help().unwrap_or(""))
+ };
+ let mut help = String::from(h) + spec_vals;
+ let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || (self.use_long && arg.name() != "");
+ debugln!("Help::help: Next Line...{:?}", nlh);
+
+ let spcs = if nlh || self.force_next_line {
+ 12 // "tab" * 3
+ } else {
+ self.longest + 12
+ };
+
+ let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w;
+
+ // Is help on next line, if so then indent
+ if nlh || self.force_next_line {
+ write!(self.writer, "\n{}{}{}", TAB, TAB, TAB)?;
+ }
+
+ debug!("Help::help: Too long...");
+ if too_long && spcs <= self.term_w || h.contains("{n}") {
+ sdebugln!("Yes");
+ debugln!("Help::help: help...{}", help);
+ debugln!("Help::help: help width...{}", str_width(&*help));
+ // Determine how many newlines we need to insert
+ let avail_chars = self.term_w - spcs;
+ debugln!("Help::help: Usable space...{}", avail_chars);
+ help = wrap_help(&help.replace("{n}", "\n"), avail_chars);
+ } else {
+ sdebugln!("No");
+ }
+ if let Some(part) = help.lines().next() {
+ write!(self.writer, "{}", part)?;
+ }
+ for part in help.lines().skip(1) {
+ write!(self.writer, "\n")?;
+ if nlh || self.force_next_line {
+ write!(self.writer, "{}{}{}", TAB, TAB, TAB)?;
+ } else if arg.has_switch() {
+ write_nspaces!(self.writer, self.longest + 12);
+ } else {
+ write_nspaces!(self.writer, self.longest + 8);
+ }
+ write!(self.writer, "{}", part)?;
+ }
+ if !help.contains('\n') && (nlh || self.force_next_line) {
+ write!(self.writer, "\n")?;
+ }
+ Ok(())
+ }
+
+ fn spec_vals(&self, a: &ArgWithDisplay) -> String {
+ debugln!("Help::spec_vals: a={}", a);
+ let mut spec_vals = vec![];
+ if let Some(ref env) = a.env() {
+ debugln!(
+ "Help::spec_vals: Found environment variable...[{:?}:{:?}]",
+ env.0,
+ env.1
+ );
+ let env_val = if !a.is_set(ArgSettings::HideEnvValues) {
+ format!(
+ "={}",
+ env.1.map_or(Cow::Borrowed(""), |val| val.to_string_lossy())
+ )
+ } else {
+ String::new()
+ };
+ let env_info = format!(" [env: {}{}]", env.0.to_string_lossy(), env_val);
+ spec_vals.push(env_info);
+ }
+ if !a.is_set(ArgSettings::HideDefaultValue) {
+ if let Some(pv) = a.default_val() {
+ debugln!("Help::spec_vals: Found default value...[{:?}]", pv);
+ spec_vals.push(format!(
+ " [default: {}]",
+ if self.color {
+ self.cizer.good(pv.to_string_lossy())
+ } else {
+ Format::None(pv.to_string_lossy())
+ }
+ ));
+ }
+ }
+ if let Some(ref aliases) = a.aliases() {
+ debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
+ spec_vals.push(format!(
+ " [aliases: {}]",
+ if self.color {
+ aliases
+ .iter()
+ .map(|v| format!("{}", self.cizer.good(v)))
+ .collect::<Vec<_>>()
+ .join(", ")
+ } else {
+ aliases.join(", ")
+ }
+ ));
+ }
+ if !self.hide_pv && !a.is_set(ArgSettings::HidePossibleValues) {
+ if let Some(pv) = a.possible_vals() {
+ debugln!("Help::spec_vals: Found possible vals...{:?}", pv);
+ spec_vals.push(if self.color {
+ format!(
+ " [possible values: {}]",
+ pv.iter()
+ .map(|v| format!("{}", self.cizer.good(v)))
+ .collect::<Vec<_>>()
+ .join(", ")
+ )
+ } else {
+ format!(" [possible values: {}]", pv.join(", "))
+ });
+ }
+ }
+ spec_vals.join(" ")
+ }
+}
+
+fn should_show_arg(use_long: bool, arg: &ArgWithOrder) -> bool {
+ if arg.is_set(ArgSettings::Hidden) {
+ return false;
+ }
+
+ (!arg.is_set(ArgSettings::HiddenLongHelp) && use_long)
+ || (!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long)
+ || arg.is_set(ArgSettings::NextLineHelp)
+}
+
+// Methods to write Parser help.
+impl<'a> Help<'a> {
+ /// Writes help for all arguments (options, flags, args, subcommands)
+ /// including titles of a Parser Object to the wrapped stream.
+ #[cfg_attr(feature = "lints", allow(useless_let_if_seq))]
+ #[cfg_attr(feature = "cargo-clippy", allow(useless_let_if_seq))]
+ pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> {
+ debugln!("Help::write_all_args;");
+ let flags = parser.has_flags();
+ let pos = parser
+ .positionals()
+ .filter(|arg| !arg.is_set(ArgSettings::Hidden))
+ .count() > 0;
+ let opts = parser.has_opts();
+ let subcmds = parser.has_visible_subcommands();
+
+ let unified_help = parser.is_set(AppSettings::UnifiedHelpMessage);
+
+ let mut first = true;
+
+ if unified_help && (flags || opts) {
+ let opts_flags = parser
+ .flags()
+ .map(as_arg_trait)
+ .chain(parser.opts().map(as_arg_trait));
+ color!(self, "OPTIONS:\n", warning)?;
+ self.write_args(opts_flags)?;
+ first = false;
+ } else {
+ if flags {
+ color!(self, "FLAGS:\n", warning)?;
+ self.write_args(parser.flags().map(as_arg_trait))?;
+ first = false;
+ }
+ if opts {
+ if !first {
+ self.writer.write_all(b"\n\n")?;
+ }
+ color!(self, "OPTIONS:\n", warning)?;
+ self.write_args(parser.opts().map(as_arg_trait))?;
+ first = false;
+ }
+ }
+
+ if pos {
+ if !first {
+ self.writer.write_all(b"\n\n")?;
+ }
+ color!(self, "ARGS:\n", warning)?;
+ self.write_args_unsorted(parser.positionals().map(as_arg_trait))?;
+ first = false;
+ }
+
+ if subcmds {
+ if !first {
+ self.writer.write_all(b"\n\n")?;
+ }
+ color!(self, "SUBCOMMANDS:\n", warning)?;
+ self.write_subcommands(parser)?;
+ }
+
+ Ok(())
+ }
+
+ /// Writes help for subcommands of a Parser Object to the wrapped stream.
+ fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> {
+ debugln!("Help::write_subcommands;");
+ // The shortest an arg can legally be is 2 (i.e. '-x')
+ self.longest = 2;
+ let mut ord_m = VecMap::new();
+ for sc in parser
+ .subcommands
+ .iter()
+ .filter(|s| !s.p.is_set(AppSettings::Hidden))
+ {
+ let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new());
+ self.longest = cmp::max(self.longest, str_width(sc.p.meta.name.as_str()));
+ //self.longest = cmp::max(self.longest, sc.p.meta.name.len());
+ btm.insert(sc.p.meta.name.clone(), sc.clone());
+ }
+
+ let mut first = true;
+ for btm in ord_m.values() {
+ for sc in btm.values() {
+ if first {
+ first = false;
+ } else {
+ self.writer.write_all(b"\n")?;
+ }
+ self.write_arg(sc)?;
+ }
+ }
+ Ok(())
+ }
+
+ /// Writes version of a Parser Object to the wrapped stream.
+ fn write_version(&mut self, parser: &Parser) -> io::Result<()> {
+ debugln!("Help::write_version;");
+ write!(self.writer, "{}", parser.meta.version.unwrap_or(""))?;
+ Ok(())
+ }
+
+ /// Writes binary name of a Parser Object to the wrapped stream.
+ fn write_bin_name(&mut self, parser: &Parser) -> io::Result<()> {
+ debugln!("Help::write_bin_name;");
+ macro_rules! write_name {
+ () => {{
+ let mut name = parser.meta.name.clone();
+ name = name.replace("{n}", "\n");
+ color!(self, wrap_help(&name, self.term_w), good)?;
+ }};
+ }
+ if let Some(bn) = parser.meta.bin_name.as_ref() {
+ if bn.contains(' ') {
+ // Incase we're dealing with subcommands i.e. git mv is translated to git-mv
+ color!(self, bn.replace(" ", "-"), good)?
+ } else {
+ write_name!();
+ }
+ } else {
+ write_name!();
+ }
+ Ok(())
+ }
+
+ /// Writes default help for a Parser Object to the wrapped stream.
+ pub fn write_default_help(&mut self, parser: &Parser) -> ClapResult<()> {
+ debugln!("Help::write_default_help;");
+ if let Some(h) = parser.meta.pre_help {
+ self.write_before_after_help(h)?;
+ self.writer.write_all(b"\n\n")?;
+ }
+
+ macro_rules! write_thing {
+ ($thing:expr) => {{
+ let mut owned_thing = $thing.to_owned();
+ owned_thing = owned_thing.replace("{n}", "\n");
+ write!(self.writer, "{}\n", wrap_help(&owned_thing, self.term_w))?
+ }};
+ }
+ // Print the version
+ self.write_bin_name(parser)?;
+ self.writer.write_all(b" ")?;
+ self.write_version(parser)?;
+ self.writer.write_all(b"\n")?;
+ if let Some(author) = parser.meta.author {
+ write_thing!(author)
+ }
+ // if self.use_long {
+ // if let Some(about) = parser.meta.long_about {
+ // debugln!("Help::write_default_help: writing long about");
+ // write_thing!(about)
+ // } else if let Some(about) = parser.meta.about {
+ // debugln!("Help::write_default_help: writing about");
+ // write_thing!(about)
+ // }
+ // } else
+ if let Some(about) = parser.meta.long_about {
+ debugln!("Help::write_default_help: writing long about");
+ write_thing!(about)
+ } else if let Some(about) = parser.meta.about {
+ debugln!("Help::write_default_help: writing about");
+ write_thing!(about)
+ }
+
+ color!(self, "\nUSAGE:", warning)?;
+ write!(
+ self.writer,
+ "\n{}{}\n\n",
+ TAB,
+ usage::create_usage_no_title(parser, &[])
+ )?;
+
+ let flags = parser.has_flags();
+ let pos = parser.has_positionals();
+ let opts = parser.has_opts();
+ let subcmds = parser.has_subcommands();
+
+ if flags || opts || pos || subcmds {
+ self.write_all_args(parser)?;
+ }
+
+ if let Some(h) = parser.meta.more_help {
+ if flags || opts || pos || subcmds {
+ self.writer.write_all(b"\n\n")?;
+ }
+ self.write_before_after_help(h)?;
+ }
+
+ self.writer.flush().map_err(Error::from)
+ }
+}
+
+/// Possible results for a copying function that stops when a given
+/// byte was found.
+enum CopyUntilResult {
+ DelimiterFound(usize),
+ DelimiterNotFound(usize),
+ ReaderEmpty,
+ ReadError(io::Error),
+ WriteError(io::Error),
+}
+
+/// Copies the contents of a reader into a writer until a delimiter byte is found.
+/// On success, the total number of bytes that were
+/// copied from reader to writer is returned.
+fn copy_until<R: Read, W: Write>(r: &mut R, w: &mut W, delimiter_byte: u8) -> CopyUntilResult {
+ debugln!("copy_until;");
+
+ let mut count = 0;
+ for wb in r.bytes() {
+ match wb {
+ Ok(b) => {
+ if b == delimiter_byte {
+ return CopyUntilResult::DelimiterFound(count);
+ }
+ match w.write(&[b]) {
+ Ok(c) => count += c,
+ Err(e) => return CopyUntilResult::WriteError(e),
+ }
+ }
+ Err(e) => return CopyUntilResult::ReadError(e),
+ }
+ }
+ if count > 0 {
+ CopyUntilResult::DelimiterNotFound(count)
+ } else {
+ CopyUntilResult::ReaderEmpty
+ }
+}
+
+/// Copies the contents of a reader into a writer until a {tag} is found,
+/// copying the tag content to a buffer and returning its size.
+/// In addition to errors, there are three possible outputs:
+/// - `None`: The reader was consumed.
+/// - `Some(Ok(0))`: No tag was captured but the reader still contains data.
+/// - `Some(Ok(length>0))`: a tag with `length` was captured to the `tag_buffer`.
+fn copy_and_capture<R: Read, W: Write>(
+ r: &mut R,
+ w: &mut W,
+ tag_buffer: &mut Cursor<Vec<u8>>,
+) -> Option<io::Result<usize>> {
+ use self::CopyUntilResult::*;
+ debugln!("copy_and_capture;");
+
+ // Find the opening byte.
+ match copy_until(r, w, b'{') {
+ // The end of the reader was reached without finding the opening tag.
+ // (either with or without having copied data to the writer)
+ // Return None indicating that we are done.
+ ReaderEmpty | DelimiterNotFound(_) => None,
+
+ // Something went wrong.
+ ReadError(e) | WriteError(e) => Some(Err(e)),
+
+ // The opening byte was found.
+ // (either with or without having copied data to the writer)
+ DelimiterFound(_) => {
+ // Lets reset the buffer first and find out how long it is.
+ tag_buffer.set_position(0);
+ let buffer_size = tag_buffer.get_ref().len();
+
+ // Find the closing byte,limiting the reader to the length of the buffer.
+ let mut rb = r.take(buffer_size as u64);
+ match copy_until(&mut rb, tag_buffer, b'}') {
+ // We were already at the end of the reader.
+ // Return None indicating that we are done.
+ ReaderEmpty => None,
+
+ // The closing tag was found.
+ // Return the tag_length.
+ DelimiterFound(tag_length) => Some(Ok(tag_length)),
+
+ // The end of the reader was found without finding the closing tag.
+ // Write the opening byte and captured text to the writer.
+ // Return 0 indicating that nothing was captured but the reader still contains data.
+ DelimiterNotFound(not_tag_length) => match w.write(b"{") {
+ Err(e) => Some(Err(e)),
+ _ => match w.write(&tag_buffer.get_ref()[0..not_tag_length]) {
+ Err(e) => Some(Err(e)),
+ _ => Some(Ok(0)),
+ },
+ },
+
+ ReadError(e) | WriteError(e) => Some(Err(e)),
+ }
+ }
+ }
+}
+
+// Methods to write Parser help using templates.
+impl<'a> Help<'a> {
+ /// Write help to stream for the parser in the format defined by the template.
+ ///
+ /// Tags arg given inside curly brackets:
+ /// Valid tags are:
+ /// * `{bin}` - Binary name.
+ /// * `{version}` - Version number.
+ /// * `{author}` - Author information.
+ /// * `{usage}` - Automatically generated or given usage string.
+ /// * `{all-args}` - Help for all arguments (options, flags, positionals arguments,
+ /// and subcommands) including titles.
+ /// * `{unified}` - Unified help for options and flags.
+ /// * `{flags}` - Help for flags.
+ /// * `{options}` - Help for options.
+ /// * `{positionals}` - Help for positionals arguments.
+ /// * `{subcommands}` - Help for subcommands.
+ /// * `{after-help}` - Info to be displayed after the help message.
+ /// * `{before-help}` - Info to be displayed before the help message.
+ ///
+ /// The template system is, on purpose, very simple. Therefore the tags have to written
+ /// in the lowercase and without spacing.
+ fn write_templated_help(&mut self, parser: &Parser, template: &str) -> ClapResult<()> {
+ debugln!("Help::write_templated_help;");
+ let mut tmplr = Cursor::new(&template);
+ let mut tag_buf = Cursor::new(vec![0u8; 15]);
+
+ // The strategy is to copy the template from the reader to wrapped stream
+ // until a tag is found. Depending on its value, the appropriate content is copied
+ // to the wrapped stream.
+ // The copy from template is then resumed, repeating this sequence until reading
+ // the complete template.
+
+ loop {
+ let tag_length = match copy_and_capture(&mut tmplr, &mut self.writer, &mut tag_buf) {
+ None => return Ok(()),
+ Some(Err(e)) => return Err(Error::from(e)),
+ Some(Ok(val)) if val > 0 => val,
+ _ => continue,
+ };
+
+ debugln!("Help::write_template_help:iter: tag_buf={};", unsafe {
+ String::from_utf8_unchecked(
+ tag_buf.get_ref()[0..tag_length]
+ .iter()
+ .map(|&i| i)
+ .collect::<Vec<_>>(),
+ )
+ });
+ match &tag_buf.get_ref()[0..tag_length] {
+ b"?" => {
+ self.writer.write_all(b"Could not decode tag name")?;
+ }
+ b"bin" => {
+ self.write_bin_name(parser)?;
+ }
+ b"version" => {
+ write!(
+ self.writer,
+ "{}",
+ parser.meta.version.unwrap_or("unknown version")
+ )?;
+ }
+ b"author" => {
+ write!(
+ self.writer,
+ "{}",
+ parser.meta.author.unwrap_or("unknown author")
+ )?;
+ }
+ b"about" => {
+ write!(
+ self.writer,
+ "{}",
+ parser.meta.about.unwrap_or("unknown about")
+ )?;
+ }
+ b"long-about" => {
+ write!(
+ self.writer,
+ "{}",
+ parser.meta.long_about.unwrap_or("unknown about")
+ )?;
+ }
+ b"usage" => {
+ write!(self.writer, "{}", usage::create_usage_no_title(parser, &[]))?;
+ }
+ b"all-args" => {
+ self.write_all_args(parser)?;
+ }
+ b"unified" => {
+ let opts_flags = parser
+ .flags()
+ .map(as_arg_trait)
+ .chain(parser.opts().map(as_arg_trait));
+ self.write_args(opts_flags)?;
+ }
+ b"flags" => {
+ self.write_args(parser.flags().map(as_arg_trait))?;
+ }
+ b"options" => {
+ self.write_args(parser.opts().map(as_arg_trait))?;
+ }
+ b"positionals" => {
+ self.write_args(parser.positionals().map(as_arg_trait))?;
+ }
+ b"subcommands" => {
+ self.write_subcommands(parser)?;
+ }
+ b"after-help" => {
+ write!(
+ self.writer,
+ "{}",
+ parser.meta.more_help.unwrap_or("unknown after-help")
+ )?;
+ }
+ b"before-help" => {
+ write!(
+ self.writer,
+ "{}",
+ parser.meta.pre_help.unwrap_or("unknown before-help")
+ )?;
+ }
+ // Unknown tag, write it back.
+ r => {
+ self.writer.write_all(b"{")?;
+ self.writer.write_all(r)?;
+ self.writer.write_all(b"}")?;
+ }
+ }
+ }
+ }
+}
+
+fn wrap_help(help: &str, avail_chars: usize) -> String {
+ let wrapper = textwrap::Wrapper::new(avail_chars).break_words(false);
+ help.lines()
+ .map(|line| wrapper.fill(line))
+ .collect::<Vec<String>>()
+ .join("\n")
+}
+
+#[cfg(test)]
+mod test {
+ use super::wrap_help;
+
+ #[test]
+ fn wrap_help_last_word() {
+ let help = String::from("foo bar baz");
+ assert_eq!(wrap_help(&help, 5), "foo\nbar\nbaz");
+ }
+}
diff --git a/clap/src/app/meta.rs b/clap/src/app/meta.rs
new file mode 100644
index 0000000..c7f128f
--- /dev/null
+++ b/clap/src/app/meta.rs
@@ -0,0 +1,33 @@
+#[doc(hidden)]
+#[allow(missing_debug_implementations)]
+#[derive(Default, Clone)]
+pub struct AppMeta<'b> {
+ pub name: String,
+ pub bin_name: Option<String>,
+ pub author: Option<&'b str>,
+ pub version: Option<&'b str>,
+ pub long_version: Option<&'b str>,
+ pub about: Option<&'b str>,
+ pub long_about: Option<&'b str>,
+ pub more_help: Option<&'b str>,
+ pub pre_help: Option<&'b str>,
+ pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
+ pub usage_str: Option<&'b str>,
+ pub usage: Option<String>,
+ pub help_str: Option<&'b str>,
+ pub disp_ord: usize,
+ pub term_w: Option<usize>,
+ pub max_w: Option<usize>,
+ pub template: Option<&'b str>,
+}
+
+impl<'b> AppMeta<'b> {
+ pub fn new() -> Self { Default::default() }
+ pub fn with_name(s: String) -> Self {
+ AppMeta {
+ name: s,
+ disp_ord: 999,
+ ..Default::default()
+ }
+ }
+}
diff --git a/clap/src/app/mod.rs b/clap/src/app/mod.rs
new file mode 100644
index 0000000..3a1a383
--- /dev/null
+++ b/clap/src/app/mod.rs
@@ -0,0 +1,1839 @@
+mod settings;
+pub mod parser;
+mod meta;
+mod help;
+mod validator;
+mod usage;
+
+// Std
+use std::env;
+use std::ffi::{OsStr, OsString};
+use std::fmt;
+use std::io::{self, BufRead, BufWriter, Write};
+use std::path::Path;
+use std::process;
+use std::rc::Rc;
+use std::result::Result as StdResult;
+
+// Third Party
+#[cfg(feature = "yaml")]
+use yaml_rust::Yaml;
+
+// Internal
+use app::help::Help;
+use app::parser::Parser;
+use args::{AnyArg, Arg, ArgGroup, ArgMatcher, ArgMatches, ArgSettings};
+use errors::Result as ClapResult;
+pub use self::settings::AppSettings;
+use completions::Shell;
+use map::{self, VecMap};
+
+/// Used to create a representation of a command line program and all possible command line
+/// arguments. Application settings are set using the "builder pattern" with the
+/// [`App::get_matches`] family of methods being the terminal methods that starts the
+/// runtime-parsing process. These methods then return information about the user supplied
+/// arguments (or lack there of).
+///
+/// **NOTE:** There aren't any mandatory "options" that one must set. The "options" may
+/// also appear in any order (so long as one of the [`App::get_matches`] methods is the last method
+/// called).
+///
+/// # Examples
+///
+/// ```no_run
+/// # use clap::{App, Arg};
+/// let m = App::new("My Program")
+/// .author("Me, me@mail.com")
+/// .version("1.0.2")
+/// .about("Explains in brief what the program does")
+/// .arg(
+/// Arg::with_name("in_file").index(1)
+/// )
+/// .after_help("Longer explanation to appear after the options when \
+/// displaying the help information from --help or -h")
+/// .get_matches();
+///
+/// // Your program logic starts here...
+/// ```
+/// [`App::get_matches`]: ./struct.App.html#method.get_matches
+#[allow(missing_debug_implementations)]
+pub struct App<'a, 'b>
+where
+ 'a: 'b,
+{
+ #[doc(hidden)] pub p: Parser<'a, 'b>,
+}
+
+
+impl<'a, 'b> App<'a, 'b> {
+ /// Creates a new instance of an application requiring a name. The name may be, but doesn't
+ /// have to be same as the binary. The name will be displayed to the user when they request to
+ /// print version or help and usage information.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// let prog = App::new("My Program")
+ /// # ;
+ /// ```
+ pub fn new<S: Into<String>>(n: S) -> Self {
+ App {
+ p: Parser::with_name(n.into()),
+ }
+ }
+
+ /// Get the name of the app
+ pub fn get_name(&self) -> &str { &self.p.meta.name }
+
+ /// Get the name of the binary
+ pub fn get_bin_name(&self) -> Option<&str> { self.p.meta.bin_name.as_ref().map(|s| s.as_str()) }
+
+ /// Creates a new instance of an application requiring a name, but uses the [`crate_authors!`]
+ /// and [`crate_version!`] macros to fill in the [`App::author`] and [`App::version`] fields.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// let prog = App::with_defaults("My Program")
+ /// # ;
+ /// ```
+ /// [`crate_authors!`]: ./macro.crate_authors!.html
+ /// [`crate_version!`]: ./macro.crate_version!.html
+ /// [`App::author`]: ./struct.App.html#method.author
+ /// [`App::version`]: ./struct.App.html#method.author
+ #[deprecated(since="2.14.1", note="Can never work; use explicit App::author() and App::version() calls instead")]
+ pub fn with_defaults<S: Into<String>>(n: S) -> Self {
+ let mut a = App {
+ p: Parser::with_name(n.into()),
+ };
+ a.p.meta.author = Some("Kevin K. <kbknapp@gmail.com>");
+ a.p.meta.version = Some("2.19.2");
+ a
+ }
+
+ /// Creates a new instance of [`App`] from a .yml (YAML) file. A full example of supported YAML
+ /// objects can be found in [`examples/17_yaml.rs`] and [`examples/17_yaml.yml`]. One great use
+ /// for using YAML is when supporting multiple languages and dialects, as each language could
+ /// be a distinct YAML file and determined at compiletime via `cargo` "features" in your
+ /// `Cargo.toml`
+ ///
+ /// In order to use this function you must compile `clap` with the `features = ["yaml"]` in
+ /// your settings for the `[dependencies.clap]` table of your `Cargo.toml`
+ ///
+ /// **NOTE:** Due to how the YAML objects are built there is a convenience macro for loading
+ /// the YAML file at compile time (relative to the current file, like modules work). That YAML
+ /// object can then be passed to this function.
+ ///
+ /// # Panics
+ ///
+ /// The YAML file must be properly formatted or this function will [`panic!`]. A good way to
+ /// ensure this doesn't happen is to run your program with the `--help` switch. If this passes
+ /// without error, you needn't worry because the YAML is properly formatted.
+ ///
+ /// # Examples
+ ///
+ /// The following example shows how to load a properly formatted YAML file to build an instance
+ /// of an [`App`] struct.
+ ///
+ /// ```ignore
+ /// # #[macro_use]
+ /// # extern crate clap;
+ /// # use clap::App;
+ /// # fn main() {
+ /// let yml = load_yaml!("app.yml");
+ /// let app = App::from_yaml(yml);
+ ///
+ /// // continued logic goes here, such as `app.get_matches()` etc.
+ /// # }
+ /// ```
+ /// [`App`]: ./struct.App.html
+ /// [`examples/17_yaml.rs`]: https://github.com/clap-rs/clap/blob/master/examples/17_yaml.rs
+ /// [`examples/17_yaml.yml`]: https://github.com/clap-rs/clap/blob/master/examples/17_yaml.yml
+ /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
+ #[cfg(feature = "yaml")]
+ pub fn from_yaml(yaml: &'a Yaml) -> App<'a, 'a> { App::from(yaml) }
+
+ /// Sets a string of author(s) that will be displayed to the user when they
+ /// request the help information with `--help` or `-h`.
+ ///
+ /// **Pro-tip:** Use `clap`s convenience macro [`crate_authors!`] to automatically set your
+ /// application's author(s) to the same thing as your crate at compile time. See the [`examples/`]
+ /// directory for more information
+ ///
+ /// See the [`examples/`]
+ /// directory for more information
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .author("Me, me@mymain.com")
+ /// # ;
+ /// ```
+ /// [`crate_authors!`]: ./macro.crate_authors!.html
+ /// [`examples/`]: https://github.com/clap-rs/clap/tree/master/examples
+ pub fn author<S: Into<&'b str>>(mut self, author: S) -> Self {
+ self.p.meta.author = Some(author.into());
+ self
+ }
+
+ /// Overrides the system-determined binary name. This should only be used when absolutely
+ /// necessary, such as when the binary name for your application is misleading, or perhaps
+ /// *not* how the user should invoke your program.
+ ///
+ /// **Pro-tip:** When building things such as third party `cargo` subcommands, this setting
+ /// **should** be used!
+ ///
+ /// **NOTE:** This command **should not** be used for [`SubCommand`]s.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("My Program")
+ /// .bin_name("my_binary")
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ pub fn bin_name<S: Into<String>>(mut self, name: S) -> Self {
+ self.p.meta.bin_name = Some(name.into());
+ self
+ }
+
+ /// Sets a string describing what the program does. This will be displayed when displaying help
+ /// information with `-h`.
+ ///
+ /// **NOTE:** If only `about` is provided, and not [`App::long_about`] but the user requests
+ /// `--help` clap will still display the contents of `about` appropriately
+ ///
+ /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be
+ /// concise
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .about("Does really amazing things to great people")
+ /// # ;
+ /// ```
+ /// [`App::long_about`]: ./struct.App.html#method.long_about
+ pub fn about<S: Into<&'b str>>(mut self, about: S) -> Self {
+ self.p.meta.about = Some(about.into());
+ self
+ }
+
+ /// Sets a string describing what the program does. This will be displayed when displaying help
+ /// information.
+ ///
+ /// **NOTE:** If only `long_about` is provided, and not [`App::about`] but the user requests
+ /// `-h` clap will still display the contents of `long_about` appropriately
+ ///
+ /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be
+ /// concise
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .long_about(
+ /// "Does really amazing things to great people. Now let's talk a little
+ /// more in depth about how this subcommand really works. It may take about
+ /// a few lines of text, but that's ok!")
+ /// # ;
+ /// ```
+ /// [`App::about`]: ./struct.App.html#method.about
+ pub fn long_about<S: Into<&'b str>>(mut self, about: S) -> Self {
+ self.p.meta.long_about = Some(about.into());
+ self
+ }
+
+ /// Sets the program's name. This will be displayed when displaying help information.
+ ///
+ /// **Pro-top:** This function is particularly useful when configuring a program via
+ /// [`App::from_yaml`] in conjunction with the [`crate_name!`] macro to derive the program's
+ /// name from its `Cargo.toml`.
+ ///
+ /// # Examples
+ /// ```ignore
+ /// # #[macro_use]
+ /// # extern crate clap;
+ /// # use clap::App;
+ /// # fn main() {
+ /// let yml = load_yaml!("app.yml");
+ /// let app = App::from_yaml(yml)
+ /// .name(crate_name!());
+ ///
+ /// // continued logic goes here, such as `app.get_matches()` etc.
+ /// # }
+ /// ```
+ ///
+ /// [`App::from_yaml`]: ./struct.App.html#method.from_yaml
+ /// [`crate_name!`]: ./macro.crate_name.html
+ pub fn name<S: Into<String>>(mut self, name: S) -> Self {
+ self.p.meta.name = name.into();
+ self
+ }
+
+ /// Adds additional help information to be displayed in addition to auto-generated help. This
+ /// information is displayed **after** the auto-generated help information. This is often used
+ /// to describe how to use the arguments, or caveats to be noted.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::App;
+ /// App::new("myprog")
+ /// .after_help("Does really amazing things to great people...but be careful with -R")
+ /// # ;
+ /// ```
+ pub fn after_help<S: Into<&'b str>>(mut self, help: S) -> Self {
+ self.p.meta.more_help = Some(help.into());
+ self
+ }
+
+ /// Adds additional help information to be displayed in addition to auto-generated help. This
+ /// information is displayed **before** the auto-generated help information. This is often used
+ /// for header information.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::App;
+ /// App::new("myprog")
+ /// .before_help("Some info I'd like to appear before the help info")
+ /// # ;
+ /// ```
+ pub fn before_help<S: Into<&'b str>>(mut self, help: S) -> Self {
+ self.p.meta.pre_help = Some(help.into());
+ self
+ }
+
+ /// Sets a string of the version number to be displayed when displaying version or help
+ /// information with `-V`.
+ ///
+ /// **NOTE:** If only `version` is provided, and not [`App::long_version`] but the user
+ /// requests `--version` clap will still display the contents of `version` appropriately
+ ///
+ /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
+ /// application's version to the same thing as your crate at compile time. See the [`examples/`]
+ /// directory for more information
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .version("v0.1.24")
+ /// # ;
+ /// ```
+ /// [`crate_version!`]: ./macro.crate_version!.html
+ /// [`examples/`]: https://github.com/clap-rs/clap/tree/master/examples
+ /// [`App::long_version`]: ./struct.App.html#method.long_version
+ pub fn version<S: Into<&'b str>>(mut self, ver: S) -> Self {
+ self.p.meta.version = Some(ver.into());
+ self
+ }
+
+ /// Sets a string of the version number to be displayed when displaying version or help
+ /// information with `--version`.
+ ///
+ /// **NOTE:** If only `long_version` is provided, and not [`App::version`] but the user
+ /// requests `-V` clap will still display the contents of `long_version` appropriately
+ ///
+ /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
+ /// application's version to the same thing as your crate at compile time. See the [`examples/`]
+ /// directory for more information
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .long_version(
+ /// "v0.1.24
+ /// commit: abcdef89726d
+ /// revision: 123
+ /// release: 2
+ /// binary: myprog")
+ /// # ;
+ /// ```
+ /// [`crate_version!`]: ./macro.crate_version!.html
+ /// [`examples/`]: https://github.com/clap-rs/clap/tree/master/examples
+ /// [`App::version`]: ./struct.App.html#method.version
+ pub fn long_version<S: Into<&'b str>>(mut self, ver: S) -> Self {
+ self.p.meta.long_version = Some(ver.into());
+ self
+ }
+
+ /// Sets a custom usage string to override the auto-generated usage string.
+ ///
+ /// This will be displayed to the user when errors are found in argument parsing, or when you
+ /// call [`ArgMatches::usage`]
+ ///
+ /// **CAUTION:** Using this setting disables `clap`s "context-aware" usage strings. After this
+ /// setting is set, this will be the only usage string displayed to the user!
+ ///
+ /// **NOTE:** You do not need to specify the "USAGE: \n\t" portion, as that will
+ /// still be applied by `clap`, you only need to specify the portion starting
+ /// with the binary name.
+ ///
+ /// **NOTE:** This will not replace the entire help message, *only* the portion
+ /// showing the usage.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .usage("myapp [-clDas] <some_file>")
+ /// # ;
+ /// ```
+ /// [`ArgMatches::usage`]: ./struct.ArgMatches.html#method.usage
+ pub fn usage<S: Into<&'b str>>(mut self, usage: S) -> Self {
+ self.p.meta.usage_str = Some(usage.into());
+ self
+ }
+
+ /// Sets a custom help message and overrides the auto-generated one. This should only be used
+ /// when the auto-generated message does not suffice.
+ ///
+ /// This will be displayed to the user when they use `--help` or `-h`
+ ///
+ /// **NOTE:** This replaces the **entire** help message, so nothing will be auto-generated.
+ ///
+ /// **NOTE:** This **only** replaces the help message for the current command, meaning if you
+ /// are using subcommands, those help messages will still be auto-generated unless you
+ /// specify a [`Arg::help`] for them as well.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myapp")
+ /// .help("myapp v1.0\n\
+ /// Does awesome things\n\
+ /// (C) me@mail.com\n\n\
+ ///
+ /// USAGE: myapp <opts> <command>\n\n\
+ ///
+ /// Options:\n\
+ /// -h, --help Display this message\n\
+ /// -V, --version Display version info\n\
+ /// -s <stuff> Do something with stuff\n\
+ /// -v Be verbose\n\n\
+ ///
+ /// Commmands:\n\
+ /// help Prints this message\n\
+ /// work Do some work")
+ /// # ;
+ /// ```
+ /// [`Arg::help`]: ./struct.Arg.html#method.help
+ pub fn help<S: Into<&'b str>>(mut self, help: S) -> Self {
+ self.p.meta.help_str = Some(help.into());
+ self
+ }
+
+ /// Sets the [`short`] for the auto-generated `help` argument.
+ ///
+ /// By default `clap` automatically assigns `h`, but this can be overridden if you have a
+ /// different argument which you'd prefer to use the `-h` short with. This can be done by
+ /// defining your own argument with a lowercase `h` as the [`short`].
+ ///
+ /// `clap` lazily generates these `help` arguments **after** you've defined any arguments of
+ /// your own.
+ ///
+ /// **NOTE:** Any leading `-` characters will be stripped, and only the first
+ /// non `-` character will be used as the [`short`] version
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .help_short("H") // Using an uppercase `H` instead of the default lowercase `h`
+ /// # ;
+ /// ```
+ /// [`short`]: ./struct.Arg.html#method.short
+ pub fn help_short<S: AsRef<str> + 'b>(mut self, s: S) -> Self {
+ self.p.help_short(s.as_ref());
+ self
+ }
+
+ /// Sets the [`short`] for the auto-generated `version` argument.
+ ///
+ /// By default `clap` automatically assigns `V`, but this can be overridden if you have a
+ /// different argument which you'd prefer to use the `-V` short with. This can be done by
+ /// defining your own argument with an uppercase `V` as the [`short`].
+ ///
+ /// `clap` lazily generates these `version` arguments **after** you've defined any arguments of
+ /// your own.
+ ///
+ /// **NOTE:** Any leading `-` characters will be stripped, and only the first
+ /// non `-` character will be used as the `short` version
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .version_short("v") // Using a lowercase `v` instead of the default capital `V`
+ /// # ;
+ /// ```
+ /// [`short`]: ./struct.Arg.html#method.short
+ pub fn version_short<S: AsRef<str>>(mut self, s: S) -> Self {
+ self.p.version_short(s.as_ref());
+ self
+ }
+
+ /// Sets the help text for the auto-generated `help` argument.
+ ///
+ /// By default `clap` sets this to `"Prints help information"`, but if you're using a
+ /// different convention for your help messages and would prefer a different phrasing you can
+ /// override it.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .help_message("Print help information") // Perhaps you want imperative help messages
+ ///
+ /// # ;
+ /// ```
+ pub fn help_message<S: Into<&'a str>>(mut self, s: S) -> Self {
+ self.p.help_message = Some(s.into());
+ self
+ }
+
+ /// Sets the help text for the auto-generated `version` argument.
+ ///
+ /// By default `clap` sets this to `"Prints version information"`, but if you're using a
+ /// different convention for your help messages and would prefer a different phrasing then you
+ /// can change it.
+ ///
+ /// # Examples
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .version_message("Print version information") // Perhaps you want imperative help messages
+ /// # ;
+ /// ```
+ pub fn version_message<S: Into<&'a str>>(mut self, s: S) -> Self {
+ self.p.version_message = Some(s.into());
+ self
+ }
+
+ /// Sets the help template to be used, overriding the default format.
+ ///
+ /// Tags arg given inside curly brackets.
+ ///
+ /// Valid tags are:
+ ///
+ /// * `{bin}` - Binary name.
+ /// * `{version}` - Version number.
+ /// * `{author}` - Author information.
+ /// * `{about}` - General description (from [`App::about`])
+ /// * `{usage}` - Automatically generated or given usage string.
+ /// * `{all-args}` - Help for all arguments (options, flags, positionals arguments,
+ /// and subcommands) including titles.
+ /// * `{unified}` - Unified help for options and flags. Note, you must *also* set
+ /// [`AppSettings::UnifiedHelpMessage`] to fully merge both options and
+ /// flags, otherwise the ordering is "best effort"
+ /// * `{flags}` - Help for flags.
+ /// * `{options}` - Help for options.
+ /// * `{positionals}` - Help for positionals arguments.
+ /// * `{subcommands}` - Help for subcommands.
+ /// * `{after-help}` - Help from [`App::after_help`]
+ /// * `{before-help}` - Help from [`App::before_help`]
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .version("1.0")
+ /// .template("{bin} ({version}) - {usage}")
+ /// # ;
+ /// ```
+ /// **NOTE:** The template system is, on purpose, very simple. Therefore the tags have to be
+ /// written in lowercase and without spacing.
+ ///
+ /// [`App::about`]: ./struct.App.html#method.about
+ /// [`App::after_help`]: ./struct.App.html#method.after_help
+ /// [`App::before_help`]: ./struct.App.html#method.before_help
+ /// [`AppSettings::UnifiedHelpMessage`]: ./enum.AppSettings.html#variant.UnifiedHelpMessage
+ pub fn template<S: Into<&'b str>>(mut self, s: S) -> Self {
+ self.p.meta.template = Some(s.into());
+ self
+ }
+
+ /// Enables a single command, or [`SubCommand`], level settings.
+ ///
+ /// See [`AppSettings`] for a full list of possibilities and examples.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::SubcommandRequired)
+ /// .setting(AppSettings::WaitOnError)
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`AppSettings`]: ./enum.AppSettings.html
+ pub fn setting(mut self, setting: AppSettings) -> Self {
+ self.p.set(setting);
+ self
+ }
+
+ /// Enables multiple command, or [`SubCommand`], level settings
+ ///
+ /// See [`AppSettings`] for a full list of possibilities and examples.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, AppSettings};
+ /// App::new("myprog")
+ /// .settings(&[AppSettings::SubcommandRequired,
+ /// AppSettings::WaitOnError])
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`AppSettings`]: ./enum.AppSettings.html
+ pub fn settings(mut self, settings: &[AppSettings]) -> Self {
+ for s in settings {
+ self.p.set(*s);
+ }
+ self
+ }
+
+ /// Enables a single setting that is propagated down through all child [`SubCommand`]s.
+ ///
+ /// See [`AppSettings`] for a full list of possibilities and examples.
+ ///
+ /// **NOTE**: The setting is *only* propagated *down* and not up through parent commands.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, AppSettings};
+ /// App::new("myprog")
+ /// .global_setting(AppSettings::SubcommandRequired)
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`AppSettings`]: ./enum.AppSettings.html
+ pub fn global_setting(mut self, setting: AppSettings) -> Self {
+ self.p.set(setting);
+ self.p.g_settings.set(setting);
+ self
+ }
+
+ /// Enables multiple settings which are propagated *down* through all child [`SubCommand`]s.
+ ///
+ /// See [`AppSettings`] for a full list of possibilities and examples.
+ ///
+ /// **NOTE**: The setting is *only* propagated *down* and not up through parent commands.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, AppSettings};
+ /// App::new("myprog")
+ /// .global_settings(&[AppSettings::SubcommandRequired,
+ /// AppSettings::ColoredHelp])
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`AppSettings`]: ./enum.AppSettings.html
+ pub fn global_settings(mut self, settings: &[AppSettings]) -> Self {
+ for s in settings {
+ self.p.set(*s);
+ self.p.g_settings.set(*s)
+ }
+ self
+ }
+
+ /// Disables a single command, or [`SubCommand`], level setting.
+ ///
+ /// See [`AppSettings`] for a full list of possibilities and examples.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, AppSettings};
+ /// App::new("myprog")
+ /// .unset_setting(AppSettings::ColorAuto)
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`AppSettings`]: ./enum.AppSettings.html
+ pub fn unset_setting(mut self, setting: AppSettings) -> Self {
+ self.p.unset(setting);
+ self
+ }
+
+ /// Disables multiple command, or [`SubCommand`], level settings.
+ ///
+ /// See [`AppSettings`] for a full list of possibilities and examples.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, AppSettings};
+ /// App::new("myprog")
+ /// .unset_settings(&[AppSettings::ColorAuto,
+ /// AppSettings::AllowInvalidUtf8])
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`AppSettings`]: ./enum.AppSettings.html
+ pub fn unset_settings(mut self, settings: &[AppSettings]) -> Self {
+ for s in settings {
+ self.p.unset(*s);
+ }
+ self
+ }
+
+ /// Sets the terminal width at which to wrap help messages. Defaults to `120`. Using `0` will
+ /// ignore terminal widths and use source formatting.
+ ///
+ /// `clap` automatically tries to determine the terminal width on Unix, Linux, macOS and Windows
+ /// if the `wrap_help` cargo "feature" has been used while compiling. If the terminal width
+ /// cannot be determined, `clap` defaults to `120`.
+ ///
+ /// **NOTE:** This setting applies globally and *not* on a per-command basis.
+ ///
+ /// **NOTE:** This setting must be set **before** any subcommands are added!
+ ///
+ /// # Platform Specific
+ ///
+ /// Only Unix, Linux, macOS and Windows support automatic determination of terminal width.
+ /// Even on those platforms, this setting is useful if for any reason the terminal width
+ /// cannot be determined.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::App;
+ /// App::new("myprog")
+ /// .set_term_width(80)
+ /// # ;
+ /// ```
+ pub fn set_term_width(mut self, width: usize) -> Self {
+ self.p.meta.term_w = Some(width);
+ self
+ }
+
+ /// Sets the max terminal width at which to wrap help messages. Using `0` will ignore terminal
+ /// widths and use source formatting.
+ ///
+ /// `clap` automatically tries to determine the terminal width on Unix, Linux, macOS and Windows
+ /// if the `wrap_help` cargo "feature" has been used while compiling, but one might want to
+ /// limit the size (e.g. when the terminal is running fullscreen).
+ ///
+ /// **NOTE:** This setting applies globally and *not* on a per-command basis.
+ ///
+ /// **NOTE:** This setting must be set **before** any subcommands are added!
+ ///
+ /// # Platform Specific
+ ///
+ /// Only Unix, Linux, macOS and Windows support automatic determination of terminal width.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::App;
+ /// App::new("myprog")
+ /// .max_term_width(100)
+ /// # ;
+ /// ```
+ pub fn max_term_width(mut self, w: usize) -> Self {
+ self.p.meta.max_w = Some(w);
+ self
+ }
+
+ /// Adds an [argument] to the list of valid possibilities.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// // Adding a single "flag" argument with a short and help text, using Arg::with_name()
+ /// .arg(
+ /// Arg::with_name("debug")
+ /// .short("d")
+ /// .help("turns on debugging mode")
+ /// )
+ /// // Adding a single "option" argument with a short, a long, and help text using the less
+ /// // verbose Arg::from_usage()
+ /// .arg(
+ /// Arg::from_usage("-c --config=[CONFIG] 'Optionally sets a config file to use'")
+ /// )
+ /// # ;
+ /// ```
+ /// [argument]: ./struct.Arg.html
+ pub fn arg<A: Into<Arg<'a, 'b>>>(mut self, a: A) -> Self {
+ self.p.add_arg(a.into());
+ self
+ }
+
+ /// Adds multiple [arguments] to the list of valid possibilities
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .args(
+ /// &[Arg::from_usage("[debug] -d 'turns on debugging info'"),
+ /// Arg::with_name("input").index(1).help("the input file to use")]
+ /// )
+ /// # ;
+ /// ```
+ /// [arguments]: ./struct.Arg.html
+ pub fn args(mut self, args: &[Arg<'a, 'b>]) -> Self {
+ for arg in args {
+ self.p.add_arg_ref(arg);
+ }
+ self
+ }
+
+ /// A convenience method for adding a single [argument] from a usage type string. The string
+ /// used follows the same rules and syntax as [`Arg::from_usage`]
+ ///
+ /// **NOTE:** The downside to using this method is that you can not set any additional
+ /// properties of the [`Arg`] other than what [`Arg::from_usage`] supports.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .arg_from_usage("-c --config=<FILE> 'Sets a configuration file to use'")
+ /// # ;
+ /// ```
+ /// [argument]: ./struct.Arg.html
+ /// [`Arg`]: ./struct.Arg.html
+ /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage
+ pub fn arg_from_usage(mut self, usage: &'a str) -> Self {
+ self.p.add_arg(Arg::from_usage(usage));
+ self
+ }
+
+ /// Adds multiple [arguments] at once from a usage string, one per line. See
+ /// [`Arg::from_usage`] for details on the syntax and rules supported.
+ ///
+ /// **NOTE:** Like [`App::arg_from_usage`] the downside is you only set properties for the
+ /// [`Arg`]s which [`Arg::from_usage`] supports.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// App::new("myprog")
+ /// .args_from_usage(
+ /// "-c --config=[FILE] 'Sets a configuration file to use'
+ /// [debug]... -d 'Sets the debugging level'
+ /// <FILE> 'The input file to use'"
+ /// )
+ /// # ;
+ /// ```
+ /// [arguments]: ./struct.Arg.html
+ /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage
+ /// [`App::arg_from_usage`]: ./struct.App.html#method.arg_from_usage
+ /// [`Arg`]: ./struct.Arg.html
+ pub fn args_from_usage(mut self, usage: &'a str) -> Self {
+ for line in usage.lines() {
+ let l = line.trim();
+ if l.is_empty() {
+ continue;
+ }
+ self.p.add_arg(Arg::from_usage(l));
+ }
+ self
+ }
+
+ /// Allows adding a [`SubCommand`] alias, which function as "hidden" subcommands that
+ /// automatically dispatch as if this subcommand was used. This is more efficient, and easier
+ /// than creating multiple hidden subcommands as one only needs to check for the existence of
+ /// this command, and not all variants.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand};
+ /// let m = App::new("myprog")
+ /// .subcommand(SubCommand::with_name("test")
+ /// .alias("do-stuff"))
+ /// .get_matches_from(vec!["myprog", "do-stuff"]);
+ /// assert_eq!(m.subcommand_name(), Some("test"));
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ pub fn alias<S: Into<&'b str>>(mut self, name: S) -> Self {
+ if let Some(ref mut als) = self.p.meta.aliases {
+ als.push((name.into(), false));
+ } else {
+ self.p.meta.aliases = Some(vec![(name.into(), false)]);
+ }
+ self
+ }
+
+ /// Allows adding [`SubCommand`] aliases, which function as "hidden" subcommands that
+ /// automatically dispatch as if this subcommand was used. This is more efficient, and easier
+ /// than creating multiple hidden subcommands as one only needs to check for the existence of
+ /// this command, and not all variants.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, SubCommand};
+ /// let m = App::new("myprog")
+ /// .subcommand(SubCommand::with_name("test")
+ /// .aliases(&["do-stuff", "do-tests", "tests"]))
+ /// .arg(Arg::with_name("input")
+ /// .help("the file to add")
+ /// .index(1)
+ /// .required(false))
+ /// .get_matches_from(vec!["myprog", "do-tests"]);
+ /// assert_eq!(m.subcommand_name(), Some("test"));
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ pub fn aliases(mut self, names: &[&'b str]) -> Self {
+ if let Some(ref mut als) = self.p.meta.aliases {
+ for n in names {
+ als.push((n, false));
+ }
+ } else {
+ self.p.meta.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
+ }
+ self
+ }
+
+ /// Allows adding a [`SubCommand`] alias that functions exactly like those defined with
+ /// [`App::alias`], except that they are visible inside the help message.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand};
+ /// let m = App::new("myprog")
+ /// .subcommand(SubCommand::with_name("test")
+ /// .visible_alias("do-stuff"))
+ /// .get_matches_from(vec!["myprog", "do-stuff"]);
+ /// assert_eq!(m.subcommand_name(), Some("test"));
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`App::alias`]: ./struct.App.html#method.alias
+ pub fn visible_alias<S: Into<&'b str>>(mut self, name: S) -> Self {
+ if let Some(ref mut als) = self.p.meta.aliases {
+ als.push((name.into(), true));
+ } else {
+ self.p.meta.aliases = Some(vec![(name.into(), true)]);
+ }
+ self
+ }
+
+ /// Allows adding multiple [`SubCommand`] aliases that functions exactly like those defined
+ /// with [`App::aliases`], except that they are visible inside the help message.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand};
+ /// let m = App::new("myprog")
+ /// .subcommand(SubCommand::with_name("test")
+ /// .visible_aliases(&["do-stuff", "tests"]))
+ /// .get_matches_from(vec!["myprog", "do-stuff"]);
+ /// assert_eq!(m.subcommand_name(), Some("test"));
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`App::aliases`]: ./struct.App.html#method.aliases
+ pub fn visible_aliases(mut self, names: &[&'b str]) -> Self {
+ if let Some(ref mut als) = self.p.meta.aliases {
+ for n in names {
+ als.push((n, true));
+ }
+ } else {
+ self.p.meta.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>());
+ }
+ self
+ }
+
+ /// Adds an [`ArgGroup`] to the application. [`ArgGroup`]s are a family of related arguments.
+ /// By placing them in a logical group, you can build easier requirement and exclusion rules.
+ /// For instance, you can make an entire [`ArgGroup`] required, meaning that one (and *only*
+ /// one) argument from that group must be present at runtime.
+ ///
+ /// You can also do things such as name an [`ArgGroup`] as a conflict to another argument.
+ /// Meaning any of the arguments that belong to that group will cause a failure if present with
+ /// the conflicting argument.
+ ///
+ /// Another added benefit of [`ArgGroup`]s is that you can extract a value from a group instead
+ /// of determining exactly which argument was used.
+ ///
+ /// Finally, using [`ArgGroup`]s to ensure exclusion between arguments is another very common
+ /// use
+ ///
+ /// # Examples
+ ///
+ /// The following example demonstrates using an [`ArgGroup`] to ensure that one, and only one,
+ /// of the arguments from the specified group is present at runtime.
+ ///
+ /// ```no_run
+ /// # use clap::{App, ArgGroup};
+ /// App::new("app")
+ /// .args_from_usage(
+ /// "--set-ver [ver] 'set the version manually'
+ /// --major 'auto increase major'
+ /// --minor 'auto increase minor'
+ /// --patch 'auto increase patch'")
+ /// .group(ArgGroup::with_name("vers")
+ /// .args(&["set-ver", "major", "minor","patch"])
+ /// .required(true))
+ /// # ;
+ /// ```
+ /// [`ArgGroup`]: ./struct.ArgGroup.html
+ pub fn group(mut self, group: ArgGroup<'a>) -> Self {
+ self.p.add_group(group);
+ self
+ }
+
+ /// Adds multiple [`ArgGroup`]s to the [`App`] at once.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, ArgGroup};
+ /// App::new("app")
+ /// .args_from_usage(
+ /// "--set-ver [ver] 'set the version manually'
+ /// --major 'auto increase major'
+ /// --minor 'auto increase minor'
+ /// --patch 'auto increase patch'
+ /// -c [FILE] 'a config file'
+ /// -i [IFACE] 'an interface'")
+ /// .groups(&[
+ /// ArgGroup::with_name("vers")
+ /// .args(&["set-ver", "major", "minor","patch"])
+ /// .required(true),
+ /// ArgGroup::with_name("input")
+ /// .args(&["c", "i"])
+ /// ])
+ /// # ;
+ /// ```
+ /// [`ArgGroup`]: ./struct.ArgGroup.html
+ /// [`App`]: ./struct.App.html
+ pub fn groups(mut self, groups: &[ArgGroup<'a>]) -> Self {
+ for g in groups {
+ self = self.group(g.into());
+ }
+ self
+ }
+
+ /// Adds a [`SubCommand`] to the list of valid possibilities. Subcommands are effectively
+ /// sub-[`App`]s, because they can contain their own arguments, subcommands, version, usage,
+ /// etc. They also function just like [`App`]s, in that they get their own auto generated help,
+ /// version, and usage.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand};
+ /// App::new("myprog")
+ /// .subcommand(SubCommand::with_name("config")
+ /// .about("Controls configuration features")
+ /// .arg_from_usage("<config> 'Required configuration file to use'"))
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`App`]: ./struct.App.html
+ pub fn subcommand(mut self, subcmd: App<'a, 'b>) -> Self {
+ self.p.add_subcommand(subcmd);
+ self
+ }
+
+ /// Adds multiple subcommands to the list of valid possibilities by iterating over an
+ /// [`IntoIterator`] of [`SubCommand`]s
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, SubCommand};
+ /// # App::new("myprog")
+ /// .subcommands( vec![
+ /// SubCommand::with_name("config").about("Controls configuration functionality")
+ /// .arg(Arg::with_name("config_file").index(1)),
+ /// SubCommand::with_name("debug").about("Controls debug functionality")])
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
+ pub fn subcommands<I>(mut self, subcmds: I) -> Self
+ where
+ I: IntoIterator<Item = App<'a, 'b>>,
+ {
+ for subcmd in subcmds {
+ self.p.add_subcommand(subcmd);
+ }
+ self
+ }
+
+ /// Allows custom ordering of [`SubCommand`]s within the help message. Subcommands with a lower
+ /// value will be displayed first in the help message. This is helpful when one would like to
+ /// emphasise frequently used subcommands, or prioritize those towards the top of the list.
+ /// Duplicate values **are** allowed. Subcommands with duplicate display orders will be
+ /// displayed in alphabetical order.
+ ///
+ /// **NOTE:** The default is 999 for all subcommands.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, SubCommand};
+ /// let m = App::new("cust-ord")
+ /// .subcommand(SubCommand::with_name("alpha") // typically subcommands are grouped
+ /// // alphabetically by name. Subcommands
+ /// // without a display_order have a value of
+ /// // 999 and are displayed alphabetically with
+ /// // all other 999 subcommands
+ /// .about("Some help and text"))
+ /// .subcommand(SubCommand::with_name("beta")
+ /// .display_order(1) // In order to force this subcommand to appear *first*
+ /// // all we have to do is give it a value lower than 999.
+ /// // Any other subcommands with a value of 1 will be displayed
+ /// // alphabetically with this one...then 2 values, then 3, etc.
+ /// .about("I should be first!"))
+ /// .get_matches_from(vec![
+ /// "cust-ord", "--help"
+ /// ]);
+ /// ```
+ ///
+ /// The above example displays the following help message
+ ///
+ /// ```text
+ /// cust-ord
+ ///
+ /// USAGE:
+ /// cust-ord [FLAGS] [OPTIONS]
+ ///
+ /// FLAGS:
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ ///
+ /// SUBCOMMANDS:
+ /// beta I should be first!
+ /// alpha Some help and text
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ pub fn display_order(mut self, ord: usize) -> Self {
+ self.p.meta.disp_ord = ord;
+ self
+ }
+
+ /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same
+ /// method as if someone ran `-h` to request the help message
+ ///
+ /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+ /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::App;
+ /// let mut app = App::new("myprog");
+ /// app.print_help();
+ /// ```
+ /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
+ /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
+ /// [`-h` (short)]: ./struct.Arg.html#method.help
+ /// [`--help` (long)]: ./struct.Arg.html#method.long_help
+ pub fn print_help(&mut self) -> ClapResult<()> {
+ // If there are global arguments, or settings we need to propagate them down to subcommands
+ // before parsing incase we run into a subcommand
+ self.p.propagate_globals();
+ self.p.propagate_settings();
+ self.p.derive_display_order();
+
+ self.p.create_help_and_version();
+ let out = io::stdout();
+ let mut buf_w = BufWriter::new(out.lock());
+ self.write_help(&mut buf_w)
+ }
+
+ /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same
+ /// method as if someone ran `--help` to request the help message
+ ///
+ /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+ /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::App;
+ /// let mut app = App::new("myprog");
+ /// app.print_long_help();
+ /// ```
+ /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
+ /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
+ /// [`-h` (short)]: ./struct.Arg.html#method.help
+ /// [`--help` (long)]: ./struct.Arg.html#method.long_help
+ pub fn print_long_help(&mut self) -> ClapResult<()> {
+ let out = io::stdout();
+ let mut buf_w = BufWriter::new(out.lock());
+ self.write_long_help(&mut buf_w)
+ }
+
+ /// Writes the full help message to the user to a [`io::Write`] object in the same method as if
+ /// the user ran `-h`
+ ///
+ /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+ /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+ ///
+ /// **NOTE:** There is a known bug where this method does not write propagated global arguments
+ /// or autogenerated arguments (i.e. the default help/version args). Prefer
+ /// [`App::write_long_help`] instead if possible!
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::App;
+ /// use std::io;
+ /// let mut app = App::new("myprog");
+ /// let mut out = io::stdout();
+ /// app.write_help(&mut out).expect("failed to write to stdout");
+ /// ```
+ /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+ /// [`-h` (short)]: ./struct.Arg.html#method.help
+ /// [`--help` (long)]: ./struct.Arg.html#method.long_help
+ pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ // PENDING ISSUE: 808
+ // https://github.com/clap-rs/clap/issues/808
+ // If there are global arguments, or settings we need to propagate them down to subcommands
+ // before parsing incase we run into a subcommand
+ // self.p.propagate_globals();
+ // self.p.propagate_settings();
+ // self.p.derive_display_order();
+ // self.p.create_help_and_version();
+
+ Help::write_app_help(w, self, false)
+ }
+
+ /// Writes the full help message to the user to a [`io::Write`] object in the same method as if
+ /// the user ran `--help`
+ ///
+ /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+ /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::App;
+ /// use std::io;
+ /// let mut app = App::new("myprog");
+ /// let mut out = io::stdout();
+ /// app.write_long_help(&mut out).expect("failed to write to stdout");
+ /// ```
+ /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+ /// [`-h` (short)]: ./struct.Arg.html#method.help
+ /// [`--help` (long)]: ./struct.Arg.html#method.long_help
+ pub fn write_long_help<W: Write>(&mut self, w: &mut W) -> ClapResult<()> {
+ // If there are global arguments, or settings we need to propagate them down to subcommands
+ // before parsing incase we run into a subcommand
+ self.p.propagate_globals();
+ self.p.propagate_settings();
+ self.p.derive_display_order();
+ self.p.create_help_and_version();
+
+ Help::write_app_help(w, self, true)
+ }
+
+ /// Writes the version message to the user to a [`io::Write`] object as if the user ran `-V`.
+ ///
+ /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
+ /// depending on if the user ran [`-V` (short)] or [`--version` (long)]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::App;
+ /// use std::io;
+ /// let mut app = App::new("myprog");
+ /// let mut out = io::stdout();
+ /// app.write_version(&mut out).expect("failed to write to stdout");
+ /// ```
+ /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+ /// [`-V` (short)]: ./struct.App.html#method.version
+ /// [`--version` (long)]: ./struct.App.html#method.long_version
+ pub fn write_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ self.p.write_version(w, false).map_err(From::from)
+ }
+
+ /// Writes the version message to the user to a [`io::Write`] object
+ ///
+ /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
+ /// depending on if the user ran [`-V` (short)] or [`--version` (long)]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::App;
+ /// use std::io;
+ /// let mut app = App::new("myprog");
+ /// let mut out = io::stdout();
+ /// app.write_long_version(&mut out).expect("failed to write to stdout");
+ /// ```
+ /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+ /// [`-V` (short)]: ./struct.App.html#method.version
+ /// [`--version` (long)]: ./struct.App.html#method.long_version
+ pub fn write_long_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ self.p.write_version(w, true).map_err(From::from)
+ }
+
+ /// Generate a completions file for a specified shell at compile time.
+ ///
+ /// **NOTE:** to generate the file at compile time you must use a `build.rs` "Build Script"
+ ///
+ /// # Examples
+ ///
+ /// The following example generates a bash completion script via a `build.rs` script. In this
+ /// simple example, we'll demo a very small application with only a single subcommand and two
+ /// args. Real applications could be many multiple levels deep in subcommands, and have tens or
+ /// potentially hundreds of arguments.
+ ///
+ /// First, it helps if we separate out our `App` definition into a separate file. Whether you
+ /// do this as a function, or bare App definition is a matter of personal preference.
+ ///
+ /// ```
+ /// // src/cli.rs
+ ///
+ /// use clap::{App, Arg, SubCommand};
+ ///
+ /// pub fn build_cli() -> App<'static, 'static> {
+ /// App::new("compl")
+ /// .about("Tests completions")
+ /// .arg(Arg::with_name("file")
+ /// .help("some input file"))
+ /// .subcommand(SubCommand::with_name("test")
+ /// .about("tests things")
+ /// .arg(Arg::with_name("case")
+ /// .long("case")
+ /// .takes_value(true)
+ /// .help("the case to test")))
+ /// }
+ /// ```
+ ///
+ /// In our regular code, we can simply call this `build_cli()` function, then call
+ /// `get_matches()`, or any of the other normal methods directly after. For example:
+ ///
+ /// ```ignore
+ /// // src/main.rs
+ ///
+ /// mod cli;
+ ///
+ /// fn main() {
+ /// let m = cli::build_cli().get_matches();
+ ///
+ /// // normal logic continues...
+ /// }
+ /// ```
+ ///
+ /// Next, we set up our `Cargo.toml` to use a `build.rs` build script.
+ ///
+ /// ```toml
+ /// # Cargo.toml
+ /// build = "build.rs"
+ ///
+ /// [build-dependencies]
+ /// clap = "2.23"
+ /// ```
+ ///
+ /// Next, we place a `build.rs` in our project root.
+ ///
+ /// ```ignore
+ /// extern crate clap;
+ ///
+ /// use clap::Shell;
+ ///
+ /// include!("src/cli.rs");
+ ///
+ /// fn main() {
+ /// let outdir = match env::var_os("OUT_DIR") {
+ /// None => return,
+ /// Some(outdir) => outdir,
+ /// };
+ /// let mut app = build_cli();
+ /// app.gen_completions("myapp", // We need to specify the bin name manually
+ /// Shell::Bash, // Then say which shell to build completions for
+ /// outdir); // Then say where write the completions to
+ /// }
+ /// ```
+ /// Now, once we compile there will be a `{bin_name}.bash` file in the directory.
+ /// Assuming we compiled with debug mode, it would be somewhere similar to
+ /// `<project>/target/debug/build/myapp-<hash>/out/myapp.bash`.
+ ///
+ /// Fish shell completions will use the file format `{bin_name}.fish`
+ pub fn gen_completions<T: Into<OsString>, S: Into<String>>(
+ &mut self,
+ bin_name: S,
+ for_shell: Shell,
+ out_dir: T,
+ ) {
+ self.p.meta.bin_name = Some(bin_name.into());
+ self.p.gen_completions(for_shell, out_dir.into());
+ }
+
+
+ /// Generate a completions file for a specified shell at runtime. Until `cargo install` can
+ /// install extra files like a completion script, this may be used e.g. in a command that
+ /// outputs the contents of the completion script, to be redirected into a file by the user.
+ ///
+ /// # Examples
+ ///
+ /// Assuming a separate `cli.rs` like the [example above](./struct.App.html#method.gen_completions),
+ /// we can let users generate a completion script using a command:
+ ///
+ /// ```ignore
+ /// // src/main.rs
+ ///
+ /// mod cli;
+ /// use std::io;
+ ///
+ /// fn main() {
+ /// let matches = cli::build_cli().get_matches();
+ ///
+ /// if matches.is_present("generate-bash-completions") {
+ /// cli::build_cli().gen_completions_to("myapp", Shell::Bash, &mut io::stdout());
+ /// }
+ ///
+ /// // normal logic continues...
+ /// }
+ ///
+ /// ```
+ ///
+ /// Usage:
+ ///
+ /// ```shell
+ /// $ myapp generate-bash-completions > /usr/share/bash-completion/completions/myapp.bash
+ /// ```
+ pub fn gen_completions_to<W: Write, S: Into<String>>(
+ &mut self,
+ bin_name: S,
+ for_shell: Shell,
+ buf: &mut W,
+ ) {
+ self.p.meta.bin_name = Some(bin_name.into());
+ self.p.gen_completions_to(for_shell, buf);
+ }
+
+ /// Starts the parsing process, upon a failed parse an error will be displayed to the user and
+ /// the process will exit with the appropriate error code. By default this method gets all user
+ /// provided arguments from [`env::args_os`] in order to allow for invalid UTF-8 code points,
+ /// which are legal on many platforms.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// let matches = App::new("myprog")
+ /// // Args and options go here...
+ /// .get_matches();
+ /// ```
+ /// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html
+ pub fn get_matches(self) -> ArgMatches<'a> { self.get_matches_from(&mut env::args_os()) }
+
+ /// Starts the parsing process. This method will return a [`clap::Result`] type instead of exiting
+ /// the process on failed parse. By default this method gets matches from [`env::args_os`]
+ ///
+ /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
+ /// used. It will return a [`clap::Error`], where the [`kind`] is a
+ /// [`ErrorKind::HelpDisplayed`] or [`ErrorKind::VersionDisplayed`] respectively. You must call
+ /// [`Error::exit`] or perform a [`std::process::exit`].
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// let matches = App::new("myprog")
+ /// // Args and options go here...
+ /// .get_matches_safe()
+ /// .unwrap_or_else( |e| e.exit() );
+ /// ```
+ /// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html
+ /// [`ErrorKind::HelpDisplayed`]: ./enum.ErrorKind.html#variant.HelpDisplayed
+ /// [`ErrorKind::VersionDisplayed`]: ./enum.ErrorKind.html#variant.VersionDisplayed
+ /// [`Error::exit`]: ./struct.Error.html#method.exit
+ /// [`std::process::exit`]: https://doc.rust-lang.org/std/process/fn.exit.html
+ /// [`clap::Result`]: ./type.Result.html
+ /// [`clap::Error`]: ./struct.Error.html
+ /// [`kind`]: ./struct.Error.html
+ pub fn get_matches_safe(self) -> ClapResult<ArgMatches<'a>> {
+ // Start the parsing
+ self.get_matches_from_safe(&mut env::args_os())
+ }
+
+ /// Starts the parsing process. Like [`App::get_matches`] this method does not return a [`clap::Result`]
+ /// and will automatically exit with an error message. This method, however, lets you specify
+ /// what iterator to use when performing matches, such as a [`Vec`] of your making.
+ ///
+ /// **NOTE:** The first argument will be parsed as the binary name unless
+ /// [`AppSettings::NoBinaryName`] is used
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
+ ///
+ /// let matches = App::new("myprog")
+ /// // Args and options go here...
+ /// .get_matches_from(arg_vec);
+ /// ```
+ /// [`App::get_matches`]: ./struct.App.html#method.get_matches
+ /// [`clap::Result`]: ./type.Result.html
+ /// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
+ /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
+ pub fn get_matches_from<I, T>(mut self, itr: I) -> ArgMatches<'a>
+ where
+ I: IntoIterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ self.get_matches_from_safe_borrow(itr).unwrap_or_else(|e| {
+ // Otherwise, write to stderr and exit
+ if e.use_stderr() {
+ wlnerr!("{}", e.message);
+ if self.p.is_set(AppSettings::WaitOnError) {
+ wlnerr!("\nPress [ENTER] / [RETURN] to continue...");
+ let mut s = String::new();
+ let i = io::stdin();
+ i.lock().read_line(&mut s).unwrap();
+ }
+ drop(self);
+ drop(e);
+ process::exit(1);
+ }
+
+ drop(self);
+ e.exit()
+ })
+ }
+
+ /// Starts the parsing process. A combination of [`App::get_matches_from`], and
+ /// [`App::get_matches_safe`]
+ ///
+ /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
+ /// used. It will return a [`clap::Error`], where the [`kind`] is a [`ErrorKind::HelpDisplayed`]
+ /// or [`ErrorKind::VersionDisplayed`] respectively. You must call [`Error::exit`] or
+ /// perform a [`std::process::exit`] yourself.
+ ///
+ /// **NOTE:** The first argument will be parsed as the binary name unless
+ /// [`AppSettings::NoBinaryName`] is used
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
+ ///
+ /// let matches = App::new("myprog")
+ /// // Args and options go here...
+ /// .get_matches_from_safe(arg_vec)
+ /// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) });
+ /// ```
+ /// [`App::get_matches_from`]: ./struct.App.html#method.get_matches_from
+ /// [`App::get_matches_safe`]: ./struct.App.html#method.get_matches_safe
+ /// [`ErrorKind::HelpDisplayed`]: ./enum.ErrorKind.html#variant.HelpDisplayed
+ /// [`ErrorKind::VersionDisplayed`]: ./enum.ErrorKind.html#variant.VersionDisplayed
+ /// [`Error::exit`]: ./struct.Error.html#method.exit
+ /// [`std::process::exit`]: https://doc.rust-lang.org/std/process/fn.exit.html
+ /// [`clap::Error`]: ./struct.Error.html
+ /// [`Error::exit`]: ./struct.Error.html#method.exit
+ /// [`kind`]: ./struct.Error.html
+ /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
+ pub fn get_matches_from_safe<I, T>(mut self, itr: I) -> ClapResult<ArgMatches<'a>>
+ where
+ I: IntoIterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ self.get_matches_from_safe_borrow(itr)
+ }
+
+ /// Starts the parsing process without consuming the [`App`] struct `self`. This is normally not
+ /// the desired functionality, instead prefer [`App::get_matches_from_safe`] which *does*
+ /// consume `self`.
+ ///
+ /// **NOTE:** The first argument will be parsed as the binary name unless
+ /// [`AppSettings::NoBinaryName`] is used
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg};
+ /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
+ ///
+ /// let mut app = App::new("myprog");
+ /// // Args and options go here...
+ /// let matches = app.get_matches_from_safe_borrow(arg_vec)
+ /// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) });
+ /// ```
+ /// [`App`]: ./struct.App.html
+ /// [`App::get_matches_from_safe`]: ./struct.App.html#method.get_matches_from_safe
+ /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
+ pub fn get_matches_from_safe_borrow<I, T>(&mut self, itr: I) -> ClapResult<ArgMatches<'a>>
+ where
+ I: IntoIterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ // If there are global arguments, or settings we need to propagate them down to subcommands
+ // before parsing incase we run into a subcommand
+ if !self.p.is_set(AppSettings::Propagated) {
+ self.p.propagate_globals();
+ self.p.propagate_settings();
+ self.p.derive_display_order();
+ self.p.set(AppSettings::Propagated);
+ }
+
+ let mut matcher = ArgMatcher::new();
+
+ let mut it = itr.into_iter();
+ // Get the name of the program (argument 1 of env::args()) and determine the
+ // actual file
+ // that was used to execute the program. This is because a program called
+ // ./target/release/my_prog -a
+ // will have two arguments, './target/release/my_prog', '-a' but we don't want
+ // to display
+ // the full path when displaying help messages and such
+ if !self.p.is_set(AppSettings::NoBinaryName) {
+ if let Some(name) = it.next() {
+ let bn_os = name.into();
+ let p = Path::new(&*bn_os);
+ if let Some(f) = p.file_name() {
+ if let Some(s) = f.to_os_string().to_str() {
+ if self.p.meta.bin_name.is_none() {
+ self.p.meta.bin_name = Some(s.to_owned());
+ }
+ }
+ }
+ }
+ }
+
+ // do the real parsing
+ if let Err(e) = self.p.get_matches_with(&mut matcher, &mut it.peekable()) {
+ return Err(e);
+ }
+
+ let global_arg_vec: Vec<&str> = (&self).p.global_args.iter().map(|ga| ga.b.name).collect();
+ matcher.propagate_globals(&global_arg_vec);
+
+ Ok(matcher.into())
+ }
+}
+
+#[cfg(feature = "yaml")]
+impl<'a> From<&'a Yaml> for App<'a, 'a> {
+ fn from(mut yaml: &'a Yaml) -> Self {
+ use args::SubCommand;
+ // We WANT this to panic on error...so expect() is good.
+ let mut is_sc = None;
+ let mut a = if let Some(name) = yaml["name"].as_str() {
+ App::new(name)
+ } else {
+ let yaml_hash = yaml.as_hash().unwrap();
+ let sc_key = yaml_hash.keys().nth(0).unwrap();
+ is_sc = Some(yaml_hash.get(sc_key).unwrap());
+ App::new(sc_key.as_str().unwrap())
+ };
+ yaml = if let Some(sc) = is_sc { sc } else { yaml };
+
+ macro_rules! yaml_str {
+ ($a:ident, $y:ident, $i:ident) => {
+ if let Some(v) = $y[stringify!($i)].as_str() {
+ $a = $a.$i(v);
+ } else if $y[stringify!($i)] != Yaml::BadValue {
+ panic!("Failed to convert YAML value {:?} to a string", $y[stringify!($i)]);
+ }
+ };
+ }
+
+ yaml_str!(a, yaml, version);
+ yaml_str!(a, yaml, long_version);
+ yaml_str!(a, yaml, author);
+ yaml_str!(a, yaml, bin_name);
+ yaml_str!(a, yaml, about);
+ yaml_str!(a, yaml, long_about);
+ yaml_str!(a, yaml, before_help);
+ yaml_str!(a, yaml, after_help);
+ yaml_str!(a, yaml, template);
+ yaml_str!(a, yaml, usage);
+ yaml_str!(a, yaml, help);
+ yaml_str!(a, yaml, help_short);
+ yaml_str!(a, yaml, version_short);
+ yaml_str!(a, yaml, help_message);
+ yaml_str!(a, yaml, version_message);
+ yaml_str!(a, yaml, alias);
+ yaml_str!(a, yaml, visible_alias);
+
+ if let Some(v) = yaml["display_order"].as_i64() {
+ a = a.display_order(v as usize);
+ } else if yaml["display_order"] != Yaml::BadValue {
+ panic!(
+ "Failed to convert YAML value {:?} to a u64",
+ yaml["display_order"]
+ );
+ }
+ if let Some(v) = yaml["setting"].as_str() {
+ a = a.setting(v.parse().expect("unknown AppSetting found in YAML file"));
+ } else if yaml["setting"] != Yaml::BadValue {
+ panic!(
+ "Failed to convert YAML value {:?} to an AppSetting",
+ yaml["setting"]
+ );
+ }
+ if let Some(v) = yaml["settings"].as_vec() {
+ for ys in v {
+ if let Some(s) = ys.as_str() {
+ a = a.setting(s.parse().expect("unknown AppSetting found in YAML file"));
+ }
+ }
+ } else if let Some(v) = yaml["settings"].as_str() {
+ a = a.setting(v.parse().expect("unknown AppSetting found in YAML file"));
+ } else if yaml["settings"] != Yaml::BadValue {
+ panic!(
+ "Failed to convert YAML value {:?} to a string",
+ yaml["settings"]
+ );
+ }
+ if let Some(v) = yaml["global_setting"].as_str() {
+ a = a.setting(v.parse().expect("unknown AppSetting found in YAML file"));
+ } else if yaml["global_setting"] != Yaml::BadValue {
+ panic!(
+ "Failed to convert YAML value {:?} to an AppSetting",
+ yaml["setting"]
+ );
+ }
+ if let Some(v) = yaml["global_settings"].as_vec() {
+ for ys in v {
+ if let Some(s) = ys.as_str() {
+ a = a.global_setting(s.parse().expect("unknown AppSetting found in YAML file"));
+ }
+ }
+ } else if let Some(v) = yaml["global_settings"].as_str() {
+ a = a.global_setting(v.parse().expect("unknown AppSetting found in YAML file"));
+ } else if yaml["global_settings"] != Yaml::BadValue {
+ panic!(
+ "Failed to convert YAML value {:?} to a string",
+ yaml["global_settings"]
+ );
+ }
+
+ macro_rules! vec_or_str {
+ ($a:ident, $y:ident, $as_vec:ident, $as_single:ident) => {{
+ let maybe_vec = $y[stringify!($as_vec)].as_vec();
+ if let Some(vec) = maybe_vec {
+ for ys in vec {
+ if let Some(s) = ys.as_str() {
+ $a = $a.$as_single(s);
+ } else {
+ panic!("Failed to convert YAML value {:?} to a string", ys);
+ }
+ }
+ } else {
+ if let Some(s) = $y[stringify!($as_vec)].as_str() {
+ $a = $a.$as_single(s);
+ } else if $y[stringify!($as_vec)] != Yaml::BadValue {
+ panic!("Failed to convert YAML value {:?} to either a vec or string", $y[stringify!($as_vec)]);
+ }
+ }
+ $a
+ }
+ };
+ }
+
+ a = vec_or_str!(a, yaml, aliases, alias);
+ a = vec_or_str!(a, yaml, visible_aliases, visible_alias);
+
+ if let Some(v) = yaml["args"].as_vec() {
+ for arg_yaml in v {
+ a = a.arg(Arg::from_yaml(arg_yaml.as_hash().unwrap()));
+ }
+ }
+ if let Some(v) = yaml["subcommands"].as_vec() {
+ for sc_yaml in v {
+ a = a.subcommand(SubCommand::from_yaml(sc_yaml));
+ }
+ }
+ if let Some(v) = yaml["groups"].as_vec() {
+ for ag_yaml in v {
+ a = a.group(ArgGroup::from(ag_yaml.as_hash().unwrap()));
+ }
+ }
+
+ a
+ }
+}
+
+impl<'a, 'b> Clone for App<'a, 'b> {
+ fn clone(&self) -> Self { App { p: self.p.clone() } }
+}
+
+impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
+ fn name(&self) -> &'n str {
+ ""
+ }
+ fn overrides(&self) -> Option<&[&'e str]> { None }
+ fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { None }
+ fn blacklist(&self) -> Option<&[&'e str]> { None }
+ fn required_unless(&self) -> Option<&[&'e str]> { None }
+ fn val_names(&self) -> Option<&VecMap<&'e str>> { None }
+ fn is_set(&self, _: ArgSettings) -> bool { false }
+ fn val_terminator(&self) -> Option<&'e str> { None }
+ fn set(&mut self, _: ArgSettings) {
+ unreachable!("App struct does not support AnyArg::set, this is a bug!")
+ }
+ fn has_switch(&self) -> bool { false }
+ fn max_vals(&self) -> Option<u64> { None }
+ fn num_vals(&self) -> Option<u64> { None }
+ fn possible_vals(&self) -> Option<&[&'e str]> { None }
+ fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> { None }
+ fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> { None }
+ fn min_vals(&self) -> Option<u64> { None }
+ fn short(&self) -> Option<char> { None }
+ fn long(&self) -> Option<&'e str> { None }
+ fn val_delim(&self) -> Option<char> { None }
+ fn takes_value(&self) -> bool { true }
+ fn help(&self) -> Option<&'e str> { self.p.meta.about }
+ fn long_help(&self) -> Option<&'e str> { self.p.meta.long_about }
+ fn default_val(&self) -> Option<&'e OsStr> { None }
+ fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
+ None
+ }
+ fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { None }
+ fn longest_filter(&self) -> bool { true }
+ fn aliases(&self) -> Option<Vec<&'e str>> {
+ if let Some(ref aliases) = self.p.meta.aliases {
+ let vis_aliases: Vec<_> = aliases
+ .iter()
+ .filter_map(|&(n, v)| if v { Some(n) } else { None })
+ .collect();
+ if vis_aliases.is_empty() {
+ None
+ } else {
+ Some(vis_aliases)
+ }
+ } else {
+ None
+ }
+ }
+}
+
+impl<'n, 'e> fmt::Display for App<'n, 'e> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.p.meta.name) }
+}
diff --git a/clap/src/app/parser.rs b/clap/src/app/parser.rs
new file mode 100644
index 0000000..decfde4
--- /dev/null
+++ b/clap/src/app/parser.rs
@@ -0,0 +1,2167 @@
+// Std
+use std::ffi::{OsStr, OsString};
+use std::fmt::Display;
+use std::fs::File;
+use std::io::{self, BufWriter, Write};
+#[cfg(all(feature = "debug", not(any(target_os = "windows", target_arch = "wasm32"))))]
+use std::os::unix::ffi::OsStrExt;
+#[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))]
+use osstringext::OsStrExt3;
+use std::path::PathBuf;
+use std::slice::Iter;
+use std::iter::Peekable;
+use std::cell::Cell;
+
+// Internal
+use INTERNAL_ERROR_MSG;
+use INVALID_UTF8;
+use SubCommand;
+use app::App;
+use app::help::Help;
+use app::meta::AppMeta;
+use app::settings::AppFlags;
+use args::{AnyArg, Arg, ArgGroup, ArgMatcher, Base, FlagBuilder, OptBuilder, PosBuilder, Switched};
+use args::settings::ArgSettings;
+use completions::ComplGen;
+use errors::{Error, ErrorKind};
+use errors::Result as ClapResult;
+use fmt::ColorWhen;
+use osstringext::OsStrExt2;
+use completions::Shell;
+use suggestions;
+use app::settings::AppSettings as AS;
+use app::validator::Validator;
+use app::usage;
+use map::{self, VecMap};
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+#[doc(hidden)]
+pub enum ParseResult<'a> {
+ Flag,
+ Opt(&'a str),
+ Pos(&'a str),
+ MaybeHyphenValue,
+ MaybeNegNum,
+ NotFound,
+ ValuesDone,
+}
+
+#[allow(missing_debug_implementations)]
+#[doc(hidden)]
+#[derive(Clone, Default)]
+pub struct Parser<'a, 'b>
+where
+ 'a: 'b,
+{
+ pub meta: AppMeta<'b>,
+ settings: AppFlags,
+ pub g_settings: AppFlags,
+ pub flags: Vec<FlagBuilder<'a, 'b>>,
+ pub opts: Vec<OptBuilder<'a, 'b>>,
+ pub positionals: VecMap<PosBuilder<'a, 'b>>,
+ pub subcommands: Vec<App<'a, 'b>>,
+ pub groups: Vec<ArgGroup<'a>>,
+ pub global_args: Vec<Arg<'a, 'b>>,
+ pub required: Vec<&'a str>,
+ pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
+ pub overrides: Vec<(&'b str, &'a str)>,
+ help_short: Option<char>,
+ version_short: Option<char>,
+ cache: Option<&'a str>,
+ pub help_message: Option<&'a str>,
+ pub version_message: Option<&'a str>,
+ cur_idx: Cell<usize>,
+}
+
+impl<'a, 'b> Parser<'a, 'b>
+where
+ 'a: 'b,
+{
+ pub fn with_name(n: String) -> Self {
+ Parser {
+ meta: AppMeta::with_name(n),
+ g_settings: AppFlags::zeroed(),
+ cur_idx: Cell::new(0),
+ ..Default::default()
+ }
+ }
+
+ pub fn help_short(&mut self, s: &str) {
+ let c = s.trim_left_matches(|c| c == '-')
+ .chars()
+ .nth(0)
+ .unwrap_or('h');
+ self.help_short = Some(c);
+ }
+
+ pub fn version_short(&mut self, s: &str) {
+ let c = s.trim_left_matches(|c| c == '-')
+ .chars()
+ .nth(0)
+ .unwrap_or('V');
+ self.version_short = Some(c);
+ }
+
+ pub fn gen_completions_to<W: Write>(&mut self, for_shell: Shell, buf: &mut W) {
+ if !self.is_set(AS::Propagated) {
+ self.propagate_help_version();
+ self.build_bin_names();
+ self.propagate_globals();
+ self.propagate_settings();
+ self.set(AS::Propagated);
+ }
+
+ ComplGen::new(self).generate(for_shell, buf)
+ }
+
+ pub fn gen_completions(&mut self, for_shell: Shell, od: OsString) {
+ use std::error::Error;
+
+ let out_dir = PathBuf::from(od);
+ let name = &*self.meta.bin_name.as_ref().unwrap().clone();
+ let file_name = match for_shell {
+ Shell::Bash => format!("{}.bash", name),
+ Shell::Fish => format!("{}.fish", name),
+ Shell::Zsh => format!("_{}", name),
+ Shell::PowerShell => format!("_{}.ps1", name),
+ Shell::Elvish => format!("{}.elv", name),
+ };
+
+ let mut file = match File::create(out_dir.join(file_name)) {
+ Err(why) => panic!("couldn't create completion file: {}", why.description()),
+ Ok(file) => file,
+ };
+ self.gen_completions_to(for_shell, &mut file)
+ }
+
+ #[inline]
+ fn app_debug_asserts(&self) -> bool {
+ assert!(self.verify_positionals());
+ let should_err = self.groups.iter().all(|g| {
+ g.args.iter().all(|arg| {
+ (self.flags.iter().any(|f| &f.b.name == arg)
+ || self.opts.iter().any(|o| &o.b.name == arg)
+ || self.positionals.values().any(|p| &p.b.name == arg)
+ || self.groups.iter().any(|g| &g.name == arg))
+ })
+ });
+ let g = self.groups.iter().find(|g| {
+ g.args.iter().any(|arg| {
+ !(self.flags.iter().any(|f| &f.b.name == arg)
+ || self.opts.iter().any(|o| &o.b.name == arg)
+ || self.positionals.values().any(|p| &p.b.name == arg)
+ || self.groups.iter().any(|g| &g.name == arg))
+ })
+ });
+ assert!(
+ should_err,
+ "The group '{}' contains the arg '{}' that doesn't actually exist.",
+ g.unwrap().name,
+ g.unwrap()
+ .args
+ .iter()
+ .find(|arg| !(self.flags.iter().any(|f| &&f.b.name == arg)
+ || self.opts.iter().any(|o| &&o.b.name == arg)
+ || self.positionals.values().any(|p| &&p.b.name == arg)
+ || self.groups.iter().any(|g| &&g.name == arg)))
+ .unwrap()
+ );
+ true
+ }
+
+ #[inline]
+ fn debug_asserts(&self, a: &Arg) -> bool {
+ assert!(
+ !arg_names!(self).any(|name| name == a.b.name),
+ format!("Non-unique argument name: {} is already in use", a.b.name)
+ );
+ if let Some(l) = a.s.long {
+ assert!(
+ !self.contains_long(l),
+ "Argument long must be unique\n\n\t--{} is already in use",
+ l
+ );
+ }
+ if let Some(s) = a.s.short {
+ assert!(
+ !self.contains_short(s),
+ "Argument short must be unique\n\n\t-{} is already in use",
+ s
+ );
+ }
+ let i = if a.index.is_none() {
+ (self.positionals.len() + 1)
+ } else {
+ a.index.unwrap() as usize
+ };
+ assert!(
+ !self.positionals.contains_key(i),
+ "Argument \"{}\" has the same index as another positional \
+ argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \
+ to take multiple values",
+ a.b.name
+ );
+ assert!(
+ !(a.is_set(ArgSettings::Required) && a.is_set(ArgSettings::Global)),
+ "Global arguments cannot be required.\n\n\t'{}' is marked as \
+ global and required",
+ a.b.name
+ );
+ if a.b.is_set(ArgSettings::Last) {
+ assert!(
+ !self.positionals
+ .values()
+ .any(|p| p.b.is_set(ArgSettings::Last)),
+ "Only one positional argument may have last(true) set. Found two."
+ );
+ assert!(a.s.long.is_none(),
+ "Flags or Options may not have last(true) set. {} has both a long and last(true) set.",
+ a.b.name);
+ assert!(a.s.short.is_none(),
+ "Flags or Options may not have last(true) set. {} has both a short and last(true) set.",
+ a.b.name);
+ }
+ true
+ }
+
+ #[inline]
+ fn add_conditional_reqs(&mut self, a: &Arg<'a, 'b>) {
+ if let Some(ref r_ifs) = a.r_ifs {
+ for &(arg, val) in r_ifs {
+ self.r_ifs.push((arg, val, a.b.name));
+ }
+ }
+ }
+
+ #[inline]
+ fn add_arg_groups(&mut self, a: &Arg<'a, 'b>) {
+ if let Some(ref grps) = a.b.groups {
+ for g in grps {
+ let mut found = false;
+ if let Some(ref mut ag) = self.groups.iter_mut().find(|grp| &grp.name == g) {
+ ag.args.push(a.b.name);
+ found = true;
+ }
+ if !found {
+ let mut ag = ArgGroup::with_name(g);
+ ag.args.push(a.b.name);
+ self.groups.push(ag);
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn add_reqs(&mut self, a: &Arg<'a, 'b>) {
+ if a.is_set(ArgSettings::Required) {
+ // If the arg is required, add all it's requirements to master required list
+ self.required.push(a.b.name);
+ if let Some(ref areqs) = a.b.requires {
+ for name in areqs
+ .iter()
+ .filter(|&&(val, _)| val.is_none())
+ .map(|&(_, name)| name)
+ {
+ self.required.push(name);
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn implied_settings(&mut self, a: &Arg<'a, 'b>) {
+ if a.is_set(ArgSettings::Last) {
+ // if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args
+ // in the usage string don't get confused or left out.
+ self.set(AS::DontCollapseArgsInUsage);
+ self.set(AS::ContainsLast);
+ }
+ if let Some(l) = a.s.long {
+ if l == "version" {
+ self.unset(AS::NeedsLongVersion);
+ } else if l == "help" {
+ self.unset(AS::NeedsLongHelp);
+ }
+ }
+ }
+
+ // actually adds the arguments
+ pub fn add_arg(&mut self, a: Arg<'a, 'b>) {
+ // if it's global we have to clone anyways
+ if a.is_set(ArgSettings::Global) {
+ return self.add_arg_ref(&a);
+ }
+ debug_assert!(self.debug_asserts(&a));
+ self.add_conditional_reqs(&a);
+ self.add_arg_groups(&a);
+ self.add_reqs(&a);
+ self.implied_settings(&a);
+ if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
+ let i = if a.index.is_none() {
+ (self.positionals.len() + 1)
+ } else {
+ a.index.unwrap() as usize
+ };
+ self.positionals
+ .insert(i, PosBuilder::from_arg(a, i as u64));
+ } else if a.is_set(ArgSettings::TakesValue) {
+ let mut ob = OptBuilder::from(a);
+ ob.s.unified_ord = self.flags.len() + self.opts.len();
+ self.opts.push(ob);
+ } else {
+ let mut fb = FlagBuilder::from(a);
+ fb.s.unified_ord = self.flags.len() + self.opts.len();
+ self.flags.push(fb);
+ }
+ }
+ // actually adds the arguments but from a borrow (which means we have to do some cloning)
+ pub fn add_arg_ref(&mut self, a: &Arg<'a, 'b>) {
+ debug_assert!(self.debug_asserts(a));
+ self.add_conditional_reqs(a);
+ self.add_arg_groups(a);
+ self.add_reqs(a);
+ self.implied_settings(a);
+ if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) {
+ let i = if a.index.is_none() {
+ (self.positionals.len() + 1)
+ } else {
+ a.index.unwrap() as usize
+ };
+ let pb = PosBuilder::from_arg_ref(a, i as u64);
+ self.positionals.insert(i, pb);
+ } else if a.is_set(ArgSettings::TakesValue) {
+ let mut ob = OptBuilder::from(a);
+ ob.s.unified_ord = self.flags.len() + self.opts.len();
+ self.opts.push(ob);
+ } else {
+ let mut fb = FlagBuilder::from(a);
+ fb.s.unified_ord = self.flags.len() + self.opts.len();
+ self.flags.push(fb);
+ }
+ if a.is_set(ArgSettings::Global) {
+ self.global_args.push(a.into());
+ }
+ }
+
+ pub fn add_group(&mut self, group: ArgGroup<'a>) {
+ if group.required {
+ self.required.push(group.name);
+ if let Some(ref reqs) = group.requires {
+ self.required.extend_from_slice(reqs);
+ }
+ // if let Some(ref bl) = group.conflicts {
+ // self.blacklist.extend_from_slice(bl);
+ // }
+ }
+ if self.groups.iter().any(|g| g.name == group.name) {
+ let grp = self.groups
+ .iter_mut()
+ .find(|g| g.name == group.name)
+ .expect(INTERNAL_ERROR_MSG);
+ grp.args.extend_from_slice(&group.args);
+ grp.requires = group.requires.clone();
+ grp.conflicts = group.conflicts.clone();
+ grp.required = group.required;
+ } else {
+ self.groups.push(group);
+ }
+ }
+
+ pub fn add_subcommand(&mut self, mut subcmd: App<'a, 'b>) {
+ debugln!(
+ "Parser::add_subcommand: term_w={:?}, name={}",
+ self.meta.term_w,
+ subcmd.p.meta.name
+ );
+ subcmd.p.meta.term_w = self.meta.term_w;
+ if subcmd.p.meta.name == "help" {
+ self.unset(AS::NeedsSubcommandHelp);
+ }
+
+ self.subcommands.push(subcmd);
+ }
+
+ pub fn propagate_settings(&mut self) {
+ debugln!(
+ "Parser::propagate_settings: self={}, g_settings={:#?}",
+ self.meta.name,
+ self.g_settings
+ );
+ for sc in &mut self.subcommands {
+ debugln!(
+ "Parser::propagate_settings: sc={}, settings={:#?}, g_settings={:#?}",
+ sc.p.meta.name,
+ sc.p.settings,
+ sc.p.g_settings
+ );
+ // We have to create a new scope in order to tell rustc the borrow of `sc` is
+ // done and to recursively call this method
+ {
+ let vsc = self.settings.is_set(AS::VersionlessSubcommands);
+ let gv = self.settings.is_set(AS::GlobalVersion);
+
+ if vsc {
+ sc.p.set(AS::DisableVersion);
+ }
+ if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() {
+ sc.p.set(AS::GlobalVersion);
+ sc.p.meta.version = Some(self.meta.version.unwrap());
+ }
+ sc.p.settings = sc.p.settings | self.g_settings;
+ sc.p.g_settings = sc.p.g_settings | self.g_settings;
+ sc.p.meta.term_w = self.meta.term_w;
+ sc.p.meta.max_w = self.meta.max_w;
+ }
+ sc.p.propagate_settings();
+ }
+ }
+
+ #[cfg_attr(feature = "lints", allow(needless_borrow))]
+ pub fn derive_display_order(&mut self) {
+ if self.is_set(AS::DeriveDisplayOrder) {
+ let unified = self.is_set(AS::UnifiedHelpMessage);
+ for (i, o) in self.opts
+ .iter_mut()
+ .enumerate()
+ .filter(|&(_, ref o)| o.s.disp_ord == 999)
+ {
+ o.s.disp_ord = if unified { o.s.unified_ord } else { i };
+ }
+ for (i, f) in self.flags
+ .iter_mut()
+ .enumerate()
+ .filter(|&(_, ref f)| f.s.disp_ord == 999)
+ {
+ f.s.disp_ord = if unified { f.s.unified_ord } else { i };
+ }
+ for (i, sc) in &mut self.subcommands
+ .iter_mut()
+ .enumerate()
+ .filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999)
+ {
+ sc.p.meta.disp_ord = i;
+ }
+ }
+ for sc in &mut self.subcommands {
+ sc.p.derive_display_order();
+ }
+ }
+
+ pub fn required(&self) -> Iter<&str> { self.required.iter() }
+
+ #[cfg_attr(feature = "lints", allow(needless_borrow))]
+ #[inline]
+ pub fn has_args(&self) -> bool {
+ !(self.flags.is_empty() && self.opts.is_empty() && self.positionals.is_empty())
+ }
+
+ #[inline]
+ pub fn has_opts(&self) -> bool { !self.opts.is_empty() }
+
+ #[inline]
+ pub fn has_flags(&self) -> bool { !self.flags.is_empty() }
+
+ #[inline]
+ pub fn has_positionals(&self) -> bool { !self.positionals.is_empty() }
+
+ #[inline]
+ pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() }
+
+ #[inline]
+ pub fn has_visible_opts(&self) -> bool {
+ if self.opts.is_empty() {
+ return false;
+ }
+ self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden))
+ }
+
+ #[inline]
+ pub fn has_visible_flags(&self) -> bool {
+ if self.flags.is_empty() {
+ return false;
+ }
+ self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden))
+ }
+
+ #[inline]
+ pub fn has_visible_positionals(&self) -> bool {
+ if self.positionals.is_empty() {
+ return false;
+ }
+ self.positionals
+ .values()
+ .any(|p| !p.is_set(ArgSettings::Hidden))
+ }
+
+ #[inline]
+ pub fn has_visible_subcommands(&self) -> bool {
+ self.has_subcommands()
+ && self.subcommands
+ .iter()
+ .filter(|sc| sc.p.meta.name != "help")
+ .any(|sc| !sc.p.is_set(AS::Hidden))
+ }
+
+ #[inline]
+ pub fn is_set(&self, s: AS) -> bool { self.settings.is_set(s) }
+
+ #[inline]
+ pub fn set(&mut self, s: AS) { self.settings.set(s) }
+
+ #[inline]
+ pub fn unset(&mut self, s: AS) { self.settings.unset(s) }
+
+ #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
+ pub fn verify_positionals(&self) -> bool {
+ // Because you must wait until all arguments have been supplied, this is the first chance
+ // to make assertions on positional argument indexes
+ //
+ // First we verify that the index highest supplied index, is equal to the number of
+ // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
+ // but no 2)
+ if let Some((idx, p)) = self.positionals.iter().rev().next() {
+ assert!(
+ !(idx != self.positionals.len()),
+ "Found positional argument \"{}\" whose index is {} but there \
+ are only {} positional arguments defined",
+ p.b.name,
+ idx,
+ self.positionals.len()
+ );
+ }
+
+ // Next we verify that only the highest index has a .multiple(true) (if any)
+ if self.positionals.values().any(|a| {
+ a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len())
+ }) {
+ let mut it = self.positionals.values().rev();
+ let last = it.next().unwrap();
+ let second_to_last = it.next().unwrap();
+ // Either the final positional is required
+ // Or the second to last has a terminator or .last(true) set
+ let ok = last.is_set(ArgSettings::Required)
+ || (second_to_last.v.terminator.is_some()
+ || second_to_last.b.is_set(ArgSettings::Last))
+ || last.is_set(ArgSettings::Last);
+ assert!(
+ ok,
+ "When using a positional argument with .multiple(true) that is *not the \
+ last* positional argument, the last positional argument (i.e the one \
+ with the highest index) *must* have .required(true) or .last(true) set."
+ );
+ let ok = second_to_last.is_set(ArgSettings::Multiple) || last.is_set(ArgSettings::Last);
+ assert!(
+ ok,
+ "Only the last positional argument, or second to last positional \
+ argument may be set to .multiple(true)"
+ );
+
+ let count = self.positionals
+ .values()
+ .filter(|p| p.b.settings.is_set(ArgSettings::Multiple) && p.v.num_vals.is_none())
+ .count();
+ let ok = count <= 1
+ || (last.is_set(ArgSettings::Last) && last.is_set(ArgSettings::Multiple)
+ && second_to_last.is_set(ArgSettings::Multiple)
+ && count == 2);
+ assert!(
+ ok,
+ "Only one positional argument with .multiple(true) set is allowed per \
+ command, unless the second one also has .last(true) set"
+ );
+ }
+
+ if self.is_set(AS::AllowMissingPositional) {
+ // Check that if a required positional argument is found, all positions with a lower
+ // index are also required.
+ let mut found = false;
+ let mut foundx2 = false;
+ for p in self.positionals.values().rev() {
+ if foundx2 && !p.b.settings.is_set(ArgSettings::Required) {
+ assert!(
+ p.b.is_set(ArgSettings::Required),
+ "Found positional argument which is not required with a lower \
+ index than a required positional argument by two or more: {:?} \
+ index {}",
+ p.b.name,
+ p.index
+ );
+ } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) {
+ // Args that .last(true) don't count since they can be required and have
+ // positionals with a lower index that aren't required
+ // Imagine: prog <req1> [opt1] -- <req2>
+ // Both of these are valid invocations:
+ // $ prog r1 -- r2
+ // $ prog r1 o1 -- r2
+ if found {
+ foundx2 = true;
+ continue;
+ }
+ found = true;
+ continue;
+ } else {
+ found = false;
+ }
+ }
+ } else {
+ // Check that if a required positional argument is found, all positions with a lower
+ // index are also required
+ let mut found = false;
+ for p in self.positionals.values().rev() {
+ if found {
+ assert!(
+ p.b.is_set(ArgSettings::Required),
+ "Found positional argument which is not required with a lower \
+ index than a required positional argument: {:?} index {}",
+ p.b.name,
+ p.index
+ );
+ } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) {
+ // Args that .last(true) don't count since they can be required and have
+ // positionals with a lower index that aren't required
+ // Imagine: prog <req1> [opt1] -- <req2>
+ // Both of these are valid invocations:
+ // $ prog r1 -- r2
+ // $ prog r1 o1 -- r2
+ found = true;
+ continue;
+ }
+ }
+ }
+ if self.positionals
+ .values()
+ .any(|p| p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required))
+ && self.has_subcommands() && !self.is_set(AS::SubcommandsNegateReqs)
+ {
+ panic!(
+ "Having a required positional argument with .last(true) set *and* child \
+ subcommands without setting SubcommandsNegateReqs isn't compatible."
+ );
+ }
+
+ true
+ }
+
+ pub fn propagate_globals(&mut self) {
+ for sc in &mut self.subcommands {
+ // We have to create a new scope in order to tell rustc the borrow of `sc` is
+ // done and to recursively call this method
+ {
+ for a in &self.global_args {
+ sc.p.add_arg_ref(a);
+ }
+ }
+ sc.p.propagate_globals();
+ }
+ }
+
+ // Checks if the arg matches a subcommand name, or any of it's aliases (if defined)
+ fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) {
+ #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
+ use std::os::unix::ffi::OsStrExt;
+ #[cfg(any(target_os = "windows", target_arch = "wasm32"))]
+ use osstringext::OsStrExt3;
+ debugln!("Parser::possible_subcommand: arg={:?}", arg_os);
+ fn starts(h: &str, n: &OsStr) -> bool {
+ let n_bytes = n.as_bytes();
+ let h_bytes = OsStr::new(h).as_bytes();
+
+ h_bytes.starts_with(n_bytes)
+ }
+
+ if self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound) {
+ return (false, None);
+ }
+ if !self.is_set(AS::InferSubcommands) {
+ if let Some(sc) = find_subcmd!(self, arg_os) {
+ return (true, Some(&sc.p.meta.name));
+ }
+ } else {
+ let v = self.subcommands
+ .iter()
+ .filter(|s| {
+ starts(&s.p.meta.name[..], &*arg_os)
+ || (s.p.meta.aliases.is_some()
+ && s.p
+ .meta
+ .aliases
+ .as_ref()
+ .unwrap()
+ .iter()
+ .filter(|&&(a, _)| starts(a, &*arg_os))
+ .count() == 1)
+ })
+ .map(|sc| &sc.p.meta.name)
+ .collect::<Vec<_>>();
+
+ for sc in &v {
+ if OsStr::new(sc) == arg_os {
+ return (true, Some(sc));
+ }
+ }
+
+ if v.len() == 1 {
+ return (true, Some(v[0]));
+ }
+ }
+ (false, None)
+ }
+
+ fn parse_help_subcommand<I, T>(&self, it: &mut I) -> ClapResult<ParseResult<'a>>
+ where
+ I: Iterator<Item = T>,
+ T: Into<OsString>,
+ {
+ debugln!("Parser::parse_help_subcommand;");
+ let cmds: Vec<OsString> = it.map(|c| c.into()).collect();
+ let mut help_help = false;
+ let mut bin_name = self.meta
+ .bin_name
+ .as_ref()
+ .unwrap_or(&self.meta.name)
+ .clone();
+ let mut sc = {
+ let mut sc: &Parser = self;
+ for (i, cmd) in cmds.iter().enumerate() {
+ if &*cmd.to_string_lossy() == "help" {
+ // cmd help help
+ help_help = true;
+ }
+ if let Some(c) = sc.subcommands
+ .iter()
+ .find(|s| &*s.p.meta.name == cmd)
+ .map(|sc| &sc.p)
+ {
+ sc = c;
+ if i == cmds.len() - 1 {
+ break;
+ }
+ } else if let Some(c) = sc.subcommands
+ .iter()
+ .find(|s| {
+ if let Some(ref als) = s.p.meta.aliases {
+ als.iter().any(|&(a, _)| a == &*cmd.to_string_lossy())
+ } else {
+ false
+ }
+ })
+ .map(|sc| &sc.p)
+ {
+ sc = c;
+ if i == cmds.len() - 1 {
+ break;
+ }
+ } else {
+ return Err(Error::unrecognized_subcommand(
+ cmd.to_string_lossy().into_owned(),
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ self.color(),
+ ));
+ }
+ bin_name = format!("{} {}", bin_name, &*sc.meta.name);
+ }
+ sc.clone()
+ };
+ if help_help {
+ let mut pb = PosBuilder::new("subcommand", 1);
+ pb.b.help = Some("The subcommand whose help message to display");
+ pb.set(ArgSettings::Multiple);
+ sc.positionals.insert(1, pb);
+ sc.settings = sc.settings | self.g_settings;
+ } else {
+ sc.create_help_and_version();
+ }
+ if sc.meta.bin_name != self.meta.bin_name {
+ sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name));
+ }
+ Err(sc._help(false))
+ }
+
+ // allow wrong self convention due to self.valid_neg_num = true and it's a private method
+ #[cfg_attr(feature = "lints", allow(wrong_self_convention))]
+ fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool {
+ debugln!("Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of);
+ let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) {
+ true
+ } else if self.is_set(AS::AllowNegativeNumbers) {
+ let a = arg_os.to_string_lossy();
+ if a.parse::<i64>().is_ok() || a.parse::<f64>().is_ok() {
+ self.set(AS::ValidNegNumFound);
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ };
+ let arg_allows_tac = match needs_val_of {
+ ParseResult::Opt(name) => {
+ let o = self.opts
+ .iter()
+ .find(|o| o.b.name == name)
+ .expect(INTERNAL_ERROR_MSG);
+ (o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
+ }
+ ParseResult::Pos(name) => {
+ let p = self.positionals
+ .values()
+ .find(|p| p.b.name == name)
+ .expect(INTERNAL_ERROR_MSG);
+ (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
+ }
+ ParseResult::ValuesDone => return true,
+ _ => false,
+ };
+ debugln!("Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac);
+
+ // Is this a new argument, or values from a previous option?
+ let mut ret = if arg_os.starts_with(b"--") {
+ debugln!("Parser::is_new_arg: -- found");
+ if arg_os.len() == 2 && !arg_allows_tac {
+ return true; // We have to return true so override everything else
+ } else if arg_allows_tac {
+ return false;
+ }
+ true
+ } else if arg_os.starts_with(b"-") {
+ debugln!("Parser::is_new_arg: - found");
+ // a singe '-' by itself is a value and typically means "stdin" on unix systems
+ !(arg_os.len() == 1)
+ } else {
+ debugln!("Parser::is_new_arg: probably value");
+ false
+ };
+
+ ret = ret && !arg_allows_tac;
+
+ debugln!("Parser::is_new_arg: starts_new_arg={:?}", ret);
+ ret
+ }
+
+ // The actual parsing function
+ #[cfg_attr(feature = "lints", allow(while_let_on_iterator, collapsible_if))]
+ pub fn get_matches_with<I, T>(
+ &mut self,
+ matcher: &mut ArgMatcher<'a>,
+ it: &mut Peekable<I>,
+ ) -> ClapResult<()>
+ where
+ I: Iterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ debugln!("Parser::get_matches_with;");
+ // Verify all positional assertions pass
+ debug_assert!(self.app_debug_asserts());
+ if self.positionals.values().any(|a| {
+ a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len())
+ })
+ && self.positionals
+ .values()
+ .last()
+ .map_or(false, |p| !p.is_set(ArgSettings::Last))
+ {
+ self.settings.set(AS::LowIndexMultiplePositional);
+ }
+ let has_args = self.has_args();
+
+ // Next we create the `--help` and `--version` arguments and add them if
+ // necessary
+ self.create_help_and_version();
+
+ let mut subcmd_name: Option<String> = None;
+ let mut needs_val_of: ParseResult<'a> = ParseResult::NotFound;
+ let mut pos_counter = 1;
+ let mut sc_is_external = false;
+ while let Some(arg) = it.next() {
+ let arg_os = arg.into();
+ debugln!(
+ "Parser::get_matches_with: Begin parsing '{:?}' ({:?})",
+ arg_os,
+ &*arg_os.as_bytes()
+ );
+
+ self.unset(AS::ValidNegNumFound);
+ // Is this a new argument, or values from a previous option?
+ let starts_new_arg = self.is_new_arg(&arg_os, needs_val_of);
+ if !self.is_set(AS::TrailingValues) && arg_os.starts_with(b"--") && arg_os.len() == 2
+ && starts_new_arg
+ {
+ debugln!("Parser::get_matches_with: setting TrailingVals=true");
+ self.set(AS::TrailingValues);
+ continue;
+ }
+
+ // Has the user already passed '--'? Meaning only positional args follow
+ if !self.is_set(AS::TrailingValues) {
+ // Does the arg match a subcommand name, or any of it's aliases (if defined)
+ {
+ match needs_val_of {
+ ParseResult::Opt(_) | ParseResult::Pos(_) => (),
+ _ => {
+ let (is_match, sc_name) = self.possible_subcommand(&arg_os);
+ debugln!(
+ "Parser::get_matches_with: possible_sc={:?}, sc={:?}",
+ is_match,
+ sc_name
+ );
+ if is_match {
+ let sc_name = sc_name.expect(INTERNAL_ERROR_MSG);
+ if sc_name == "help" && self.is_set(AS::NeedsSubcommandHelp) {
+ self.parse_help_subcommand(it)?;
+ }
+ subcmd_name = Some(sc_name.to_owned());
+ break;
+ }
+ }
+ }
+ }
+
+ if starts_new_arg {
+ let check_all = self.is_set(AS::AllArgsOverrideSelf);
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(
+ any_arg,
+ &mut self.overrides,
+ &mut self.required,
+ check_all,
+ );
+ }
+
+ if arg_os.starts_with(b"--") {
+ needs_val_of = self.parse_long_arg(matcher, &arg_os, it)?;
+ debugln!(
+ "Parser:get_matches_with: After parse_long_arg {:?}",
+ needs_val_of
+ );
+ match needs_val_of {
+ ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => {
+ continue
+ }
+ _ => (),
+ }
+ } else if arg_os.starts_with(b"-") && arg_os.len() != 1 {
+ // Try to parse short args like normal, if AllowLeadingHyphen or
+ // AllowNegativeNumbers is set, parse_short_arg will *not* throw
+ // an error, and instead return Ok(None)
+ needs_val_of = self.parse_short_arg(matcher, &arg_os)?;
+ // If it's None, we then check if one of those two AppSettings was set
+ debugln!(
+ "Parser:get_matches_with: After parse_short_arg {:?}",
+ needs_val_of
+ );
+ match needs_val_of {
+ ParseResult::MaybeNegNum => {
+ if !(arg_os.to_string_lossy().parse::<i64>().is_ok()
+ || arg_os.to_string_lossy().parse::<f64>().is_ok())
+ {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ }
+ ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => {
+ continue
+ }
+ _ => (),
+ }
+ }
+ } else {
+ if let ParseResult::Opt(name) = needs_val_of {
+ // Check to see if parsing a value from a previous arg
+ let arg = self.opts
+ .iter()
+ .find(|o| o.b.name == name)
+ .expect(INTERNAL_ERROR_MSG);
+ // get the OptBuilder so we can check the settings
+ needs_val_of = self.add_val_to_arg(arg, &arg_os, matcher)?;
+ // get the next value from the iterator
+ continue;
+ }
+ }
+ }
+
+ if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound))
+ && !self.is_set(AS::InferSubcommands) && !self.is_set(AS::AllowExternalSubcommands)
+ {
+ if let Some(cdate) =
+ suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self))
+ {
+ return Err(Error::invalid_subcommand(
+ arg_os.to_string_lossy().into_owned(),
+ cdate,
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ }
+
+ let low_index_mults = self.is_set(AS::LowIndexMultiplePositional)
+ && pos_counter == (self.positionals.len() - 1);
+ let missing_pos = self.is_set(AS::AllowMissingPositional)
+ && (pos_counter == (self.positionals.len() - 1)
+ && !self.is_set(AS::TrailingValues));
+ debugln!(
+ "Parser::get_matches_with: Positional counter...{}",
+ pos_counter
+ );
+ debugln!(
+ "Parser::get_matches_with: Low index multiples...{:?}",
+ low_index_mults
+ );
+ if low_index_mults || missing_pos {
+ if let Some(na) = it.peek() {
+ let n = (*na).clone().into();
+ needs_val_of = if needs_val_of != ParseResult::ValuesDone {
+ if let Some(p) = self.positionals.get(pos_counter) {
+ ParseResult::Pos(p.b.name)
+ } else {
+ ParseResult::ValuesDone
+ }
+ } else {
+ ParseResult::ValuesDone
+ };
+ let sc_match = { self.possible_subcommand(&n).0 };
+ if self.is_new_arg(&n, needs_val_of) || sc_match
+ || suggestions::did_you_mean(&n.to_string_lossy(), sc_names!(self))
+ .is_some()
+ {
+ debugln!("Parser::get_matches_with: Bumping the positional counter...");
+ pos_counter += 1;
+ }
+ } else {
+ debugln!("Parser::get_matches_with: Bumping the positional counter...");
+ pos_counter += 1;
+ }
+ } else if (self.is_set(AS::AllowMissingPositional) && self.is_set(AS::TrailingValues))
+ || (self.is_set(AS::ContainsLast) && self.is_set(AS::TrailingValues))
+ {
+ // Came to -- and one postional has .last(true) set, so we go immediately
+ // to the last (highest index) positional
+ debugln!("Parser::get_matches_with: .last(true) and --, setting last pos");
+ pos_counter = self.positionals.len();
+ }
+ if let Some(p) = self.positionals.get(pos_counter) {
+ if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ if !self.is_set(AS::TrailingValues)
+ && (self.is_set(AS::TrailingVarArg) && pos_counter == self.positionals.len())
+ {
+ self.settings.set(AS::TrailingValues);
+ }
+ if self.cache.map_or(true, |name| name != p.b.name) {
+ let check_all = self.is_set(AS::AllArgsOverrideSelf);
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(
+ any_arg,
+ &mut self.overrides,
+ &mut self.required,
+ check_all,
+ );
+ }
+ self.cache = Some(p.b.name);
+ }
+ let _ = self.add_val_to_arg(p, &arg_os, matcher)?;
+
+ matcher.inc_occurrence_of(p.b.name);
+ let _ = self.groups_for_arg(p.b.name)
+ .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+
+ self.settings.set(AS::ValidArgFound);
+ // Only increment the positional counter if it doesn't allow multiples
+ if !p.b.settings.is_set(ArgSettings::Multiple) {
+ pos_counter += 1;
+ }
+ self.settings.set(AS::ValidArgFound);
+ } else if self.is_set(AS::AllowExternalSubcommands) {
+ // Get external subcommand name
+ let sc_name = match arg_os.to_str() {
+ Some(s) => s.to_string(),
+ None => {
+ if !self.is_set(AS::StrictUtf8) {
+ return Err(Error::invalid_utf8(
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ arg_os.to_string_lossy().into_owned()
+ }
+ };
+
+ // Collect the external subcommand args
+ let mut sc_m = ArgMatcher::new();
+ while let Some(v) = it.next() {
+ let a = v.into();
+ if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) {
+ return Err(Error::invalid_utf8(
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ sc_m.add_val_to("", &a);
+ }
+
+ matcher.subcommand(SubCommand {
+ name: sc_name,
+ matches: sc_m.into(),
+ });
+ sc_is_external = true;
+ } else if !((self.is_set(AS::AllowLeadingHyphen)
+ || self.is_set(AS::AllowNegativeNumbers))
+ && arg_os.starts_with(b"-"))
+ && !self.is_set(AS::InferSubcommands)
+ {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ } else if !has_args || self.is_set(AS::InferSubcommands) && self.has_subcommands() {
+ if let Some(cdate) =
+ suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self))
+ {
+ return Err(Error::invalid_subcommand(
+ arg_os.to_string_lossy().into_owned(),
+ cdate,
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ } else {
+ return Err(Error::unrecognized_subcommand(
+ arg_os.to_string_lossy().into_owned(),
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ self.color(),
+ ));
+ }
+ } else {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ }
+
+ if !sc_is_external {
+ if let Some(ref pos_sc_name) = subcmd_name {
+ let sc_name = {
+ find_subcmd!(self, pos_sc_name)
+ .expect(INTERNAL_ERROR_MSG)
+ .p
+ .meta
+ .name
+ .clone()
+ };
+ self.parse_subcommand(&*sc_name, matcher, it)?;
+ } else if self.is_set(AS::SubcommandRequired) {
+ let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
+ return Err(Error::missing_subcommand(
+ bn,
+ &usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ } else if self.is_set(AS::SubcommandRequiredElseHelp) {
+ debugln!("Parser::get_matches_with: SubcommandRequiredElseHelp=true");
+ let mut out = vec![];
+ self.write_help_err(&mut out)?;
+ return Err(Error {
+ message: String::from_utf8_lossy(&*out).into_owned(),
+ kind: ErrorKind::MissingArgumentOrSubcommand,
+ info: None,
+ });
+ }
+ }
+
+ // In case the last arg was new, we need to process it's overrides
+ let check_all = self.is_set(AS::AllArgsOverrideSelf);
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(
+ any_arg,
+ &mut self.overrides,
+ &mut self.required,
+ check_all,
+ );
+ }
+
+ self.remove_overrides(matcher);
+
+ Validator::new(self).validate(needs_val_of, subcmd_name, matcher)
+ }
+
+ fn remove_overrides(&mut self, matcher: &mut ArgMatcher) {
+ debugln!("Parser::remove_overrides:{:?};", self.overrides);
+ for &(overr, name) in &self.overrides {
+ debugln!("Parser::remove_overrides:iter:({},{});", overr, name);
+ if matcher.is_present(overr) {
+ debugln!(
+ "Parser::remove_overrides:iter:({},{}): removing {};",
+ overr,
+ name,
+ name
+ );
+ matcher.remove(name);
+ for i in (0..self.required.len()).rev() {
+ debugln!(
+ "Parser::remove_overrides:iter:({},{}): removing required {};",
+ overr,
+ name,
+ name
+ );
+ if self.required[i] == name {
+ self.required.swap_remove(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ fn propagate_help_version(&mut self) {
+ debugln!("Parser::propagate_help_version;");
+ self.create_help_and_version();
+ for sc in &mut self.subcommands {
+ sc.p.propagate_help_version();
+ }
+ }
+
+ fn build_bin_names(&mut self) {
+ debugln!("Parser::build_bin_names;");
+ for sc in &mut self.subcommands {
+ debug!("Parser::build_bin_names:iter: bin_name set...");
+ if sc.p.meta.bin_name.is_none() {
+ sdebugln!("No");
+ let bin_name = format!(
+ "{}{}{}",
+ self.meta
+ .bin_name
+ .as_ref()
+ .unwrap_or(&self.meta.name.clone()),
+ if self.meta.bin_name.is_some() {
+ " "
+ } else {
+ ""
+ },
+ &*sc.p.meta.name
+ );
+ debugln!(
+ "Parser::build_bin_names:iter: Setting bin_name of {} to {}",
+ self.meta.name,
+ bin_name
+ );
+ sc.p.meta.bin_name = Some(bin_name);
+ } else {
+ sdebugln!("yes ({:?})", sc.p.meta.bin_name);
+ }
+ debugln!(
+ "Parser::build_bin_names:iter: Calling build_bin_names from...{}",
+ sc.p.meta.name
+ );
+ sc.p.build_bin_names();
+ }
+ }
+
+ fn parse_subcommand<I, T>(
+ &mut self,
+ sc_name: &str,
+ matcher: &mut ArgMatcher<'a>,
+ it: &mut Peekable<I>,
+ ) -> ClapResult<()>
+ where
+ I: Iterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ use std::fmt::Write;
+ debugln!("Parser::parse_subcommand;");
+ let mut mid_string = String::new();
+ if !self.is_set(AS::SubcommandsNegateReqs) {
+ let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect();
+ for k in matcher.arg_names() {
+ hs.push(k);
+ }
+ let reqs = usage::get_required_usage_from(self, &hs, Some(matcher), None, false);
+
+ for s in &reqs {
+ write!(&mut mid_string, " {}", s).expect(INTERNAL_ERROR_MSG);
+ }
+ }
+ mid_string.push_str(" ");
+ if let Some(ref mut sc) = self.subcommands
+ .iter_mut()
+ .find(|s| s.p.meta.name == sc_name)
+ {
+ let mut sc_matcher = ArgMatcher::new();
+ // bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
+ // a space
+ sc.p.meta.usage = Some(format!(
+ "{}{}{}",
+ self.meta.bin_name.as_ref().unwrap_or(&String::new()),
+ if self.meta.bin_name.is_some() {
+ &*mid_string
+ } else {
+ ""
+ },
+ &*sc.p.meta.name
+ ));
+ sc.p.meta.bin_name = Some(format!(
+ "{}{}{}",
+ self.meta.bin_name.as_ref().unwrap_or(&String::new()),
+ if self.meta.bin_name.is_some() {
+ " "
+ } else {
+ ""
+ },
+ &*sc.p.meta.name
+ ));
+ debugln!(
+ "Parser::parse_subcommand: About to parse sc={}",
+ sc.p.meta.name
+ );
+ debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
+ sc.p.get_matches_with(&mut sc_matcher, it)?;
+ matcher.subcommand(SubCommand {
+ name: sc.p.meta.name.clone(),
+ matches: sc_matcher.into(),
+ });
+ }
+ Ok(())
+ }
+
+ pub fn groups_for_arg(&self, name: &str) -> Option<Vec<&'a str>> {
+ debugln!("Parser::groups_for_arg: name={}", name);
+
+ if self.groups.is_empty() {
+ debugln!("Parser::groups_for_arg: No groups defined");
+ return None;
+ }
+ let mut res = vec![];
+ debugln!("Parser::groups_for_arg: Searching through groups...");
+ for grp in &self.groups {
+ for a in &grp.args {
+ if a == &name {
+ sdebugln!("\tFound '{}'", grp.name);
+ res.push(&*grp.name);
+ }
+ }
+ }
+ if res.is_empty() {
+ return None;
+ }
+
+ Some(res)
+ }
+
+ pub fn args_in_group(&self, group: &str) -> Vec<String> {
+ debug_assert!(self.app_debug_asserts());
+
+ let mut g_vec = vec![];
+ let mut args = vec![];
+
+ for n in &self.groups
+ .iter()
+ .find(|g| g.name == group)
+ .expect(INTERNAL_ERROR_MSG)
+ .args
+ {
+ if let Some(f) = self.flags.iter().find(|f| &f.b.name == n) {
+ args.push(f.to_string());
+ } else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) {
+ args.push(f.to_string());
+ } else if let Some(p) = self.positionals.values().find(|p| &p.b.name == n) {
+ args.push(p.b.name.to_owned());
+ } else {
+ g_vec.push(*n);
+ }
+ }
+
+ for av in g_vec.iter().map(|g| self.args_in_group(g)) {
+ args.extend(av);
+ }
+ args.dedup();
+ args.iter().map(ToOwned::to_owned).collect()
+ }
+
+ pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> {
+ let mut g_vec = vec![];
+ let mut args = vec![];
+
+ for n in &self.groups
+ .iter()
+ .find(|g| g.name == group)
+ .expect(INTERNAL_ERROR_MSG)
+ .args
+ {
+ if self.groups.iter().any(|g| g.name == *n) {
+ args.extend(self.arg_names_in_group(n));
+ g_vec.push(*n);
+ } else if !args.contains(n) {
+ args.push(*n);
+ }
+ }
+
+ args.iter().map(|s| *s).collect()
+ }
+
+ pub fn create_help_and_version(&mut self) {
+ debugln!("Parser::create_help_and_version;");
+ // name is "hclap_help" because flags are sorted by name
+ if !self.is_set(AS::DisableHelpFlags) && !self.contains_long("help") {
+ debugln!("Parser::create_help_and_version: Building --help");
+ if self.help_short.is_none() && !self.contains_short('h') {
+ self.help_short = Some('h');
+ }
+ let arg = FlagBuilder {
+ b: Base {
+ name: "hclap_help",
+ help: self.help_message.or(Some("Prints help information")),
+ ..Default::default()
+ },
+ s: Switched {
+ short: self.help_short,
+ long: Some("help"),
+ ..Default::default()
+ },
+ };
+ self.flags.push(arg);
+ }
+ if !self.is_set(AS::DisableVersion) && !self.contains_long("version") {
+ debugln!("Parser::create_help_and_version: Building --version");
+ if self.version_short.is_none() && !self.contains_short('V') {
+ self.version_short = Some('V');
+ }
+ // name is "vclap_version" because flags are sorted by name
+ let arg = FlagBuilder {
+ b: Base {
+ name: "vclap_version",
+ help: self.version_message.or(Some("Prints version information")),
+ ..Default::default()
+ },
+ s: Switched {
+ short: self.version_short,
+ long: Some("version"),
+ ..Default::default()
+ },
+ };
+ self.flags.push(arg);
+ }
+ if !self.subcommands.is_empty() && !self.is_set(AS::DisableHelpSubcommand)
+ && self.is_set(AS::NeedsSubcommandHelp)
+ {
+ debugln!("Parser::create_help_and_version: Building help");
+ self.subcommands.push(
+ App::new("help")
+ .about("Prints this message or the help of the given subcommand(s)"),
+ );
+ }
+ }
+
+ // Retrieves the names of all args the user has supplied thus far, except required ones
+ // because those will be listed in self.required
+ fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> {
+ debugln!("Parser::check_for_help_and_version_str;");
+ debug!(
+ "Parser::check_for_help_and_version_str: Checking if --{} is help or version...",
+ arg.to_str().unwrap()
+ );
+ if arg == "help" && self.is_set(AS::NeedsLongHelp) {
+ sdebugln!("Help");
+ return Err(self._help(true));
+ }
+ if arg == "version" && self.is_set(AS::NeedsLongVersion) {
+ sdebugln!("Version");
+ return Err(self._version(true));
+ }
+ sdebugln!("Neither");
+
+ Ok(())
+ }
+
+ fn check_for_help_and_version_char(&self, arg: char) -> ClapResult<()> {
+ debugln!("Parser::check_for_help_and_version_char;");
+ debug!(
+ "Parser::check_for_help_and_version_char: Checking if -{} is help or version...",
+ arg
+ );
+ if let Some(h) = self.help_short {
+ if arg == h && self.is_set(AS::NeedsLongHelp) {
+ sdebugln!("Help");
+ return Err(self._help(false));
+ }
+ }
+ if let Some(v) = self.version_short {
+ if arg == v && self.is_set(AS::NeedsLongVersion) {
+ sdebugln!("Version");
+ return Err(self._version(false));
+ }
+ }
+ sdebugln!("Neither");
+ Ok(())
+ }
+
+ fn use_long_help(&self) -> bool {
+ // In this case, both must be checked. This allows the retention of
+ // original formatting, but also ensures that the actual -h or --help
+ // specified by the user is sent through. If HiddenShortHelp is not included,
+ // then items specified with hidden_short_help will also be hidden.
+ let should_long = |v: &Base| {
+ v.long_help.is_some() ||
+ v.is_set(ArgSettings::HiddenLongHelp) ||
+ v.is_set(ArgSettings::HiddenShortHelp)
+ };
+
+ self.meta.long_about.is_some()
+ || self.flags.iter().any(|f| should_long(&f.b))
+ || self.opts.iter().any(|o| should_long(&o.b))
+ || self.positionals.values().any(|p| should_long(&p.b))
+ || self.subcommands
+ .iter()
+ .any(|s| s.p.meta.long_about.is_some())
+ }
+
+ fn _help(&self, mut use_long: bool) -> Error {
+ debugln!("Parser::_help: use_long={:?}", use_long);
+ use_long = use_long && self.use_long_help();
+ let mut buf = vec![];
+ match Help::write_parser_help(&mut buf, self, use_long) {
+ Err(e) => e,
+ _ => Error {
+ message: String::from_utf8(buf).unwrap_or_default(),
+ kind: ErrorKind::HelpDisplayed,
+ info: None,
+ },
+ }
+ }
+
+ fn _version(&self, use_long: bool) -> Error {
+ debugln!("Parser::_version: ");
+ let out = io::stdout();
+ let mut buf_w = BufWriter::new(out.lock());
+ match self.print_version(&mut buf_w, use_long) {
+ Err(e) => e,
+ _ => Error {
+ message: String::new(),
+ kind: ErrorKind::VersionDisplayed,
+ info: None,
+ },
+ }
+ }
+
+ fn parse_long_arg<I, T>(
+ &mut self,
+ matcher: &mut ArgMatcher<'a>,
+ full_arg: &OsStr,
+ it: &mut Peekable<I>,
+ ) -> ClapResult<ParseResult<'a>>
+ where
+ I: Iterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ // maybe here lifetime should be 'a
+ debugln!("Parser::parse_long_arg;");
+
+ // Update the current index
+ self.cur_idx.set(self.cur_idx.get() + 1);
+
+ let mut val = None;
+ debug!("Parser::parse_long_arg: Does it contain '='...");
+ let arg = if full_arg.contains_byte(b'=') {
+ let (p0, p1) = full_arg.trim_left_matches(b'-').split_at_byte(b'=');
+ sdebugln!("Yes '{:?}'", p1);
+ val = Some(p1);
+ p0
+ } else {
+ sdebugln!("No");
+ full_arg.trim_left_matches(b'-')
+ };
+
+ if let Some(opt) = find_opt_by_long!(@os self, arg) {
+ debugln!(
+ "Parser::parse_long_arg: Found valid opt '{}'",
+ opt.to_string()
+ );
+ self.settings.set(AS::ValidArgFound);
+ let ret = self.parse_opt(val, opt, val.is_some(), matcher)?;
+ if self.cache.map_or(true, |name| name != opt.b.name) {
+ self.cache = Some(opt.b.name);
+ }
+
+ return Ok(ret);
+ } else if let Some(flag) = find_flag_by_long!(@os self, arg) {
+ debugln!(
+ "Parser::parse_long_arg: Found valid flag '{}'",
+ flag.to_string()
+ );
+ self.settings.set(AS::ValidArgFound);
+ // Only flags could be help or version, and we need to check the raw long
+ // so this is the first point to check
+ self.check_for_help_and_version_str(arg)?;
+
+ self.parse_flag(flag, matcher)?;
+
+ // Handle conflicts, requirements, etc.
+ if self.cache.map_or(true, |name| name != flag.b.name) {
+ self.cache = Some(flag.b.name);
+ }
+
+ return Ok(ParseResult::Flag);
+ } else if self.is_set(AS::AllowLeadingHyphen) {
+ return Ok(ParseResult::MaybeHyphenValue);
+ } else if self.is_set(AS::ValidNegNumFound) {
+ return Ok(ParseResult::MaybeNegNum);
+ }
+
+ debugln!("Parser::parse_long_arg: Didn't match anything");
+
+ let args_rest: Vec<_> = it.map(|x| x.clone().into()).collect();
+ let args_rest2: Vec<_> = args_rest.iter().map(|x| x.to_str().expect(INVALID_UTF8)).collect();
+ self.did_you_mean_error(
+ arg.to_str().expect(INVALID_UTF8),
+ matcher,
+ &args_rest2[..]
+ ).map(|_| ParseResult::NotFound)
+ }
+
+ #[cfg_attr(feature = "lints", allow(len_zero))]
+ fn parse_short_arg(
+ &mut self,
+ matcher: &mut ArgMatcher<'a>,
+ full_arg: &OsStr,
+ ) -> ClapResult<ParseResult<'a>> {
+ debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg);
+ let arg_os = full_arg.trim_left_matches(b'-');
+ let arg = arg_os.to_string_lossy();
+
+ // If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not
+ // `-v` `-a` `-l` assuming `v` `a` and `l` are all, or mostly, valid shorts.
+ if self.is_set(AS::AllowLeadingHyphen) {
+ if arg.chars().any(|c| !self.contains_short(c)) {
+ debugln!(
+ "Parser::parse_short_arg: LeadingHyphenAllowed yet -{} isn't valid",
+ arg
+ );
+ return Ok(ParseResult::MaybeHyphenValue);
+ }
+ } else if self.is_set(AS::ValidNegNumFound) {
+ // TODO: Add docs about having AllowNegativeNumbers and `-2` as a valid short
+ // May be better to move this to *after* not finding a valid flag/opt?
+ debugln!("Parser::parse_short_arg: Valid negative num...");
+ return Ok(ParseResult::MaybeNegNum);
+ }
+
+ let mut ret = ParseResult::NotFound;
+ for c in arg.chars() {
+ debugln!("Parser::parse_short_arg:iter:{}", c);
+
+ // update each index because `-abcd` is four indices to clap
+ self.cur_idx.set(self.cur_idx.get() + 1);
+
+ // Check for matching short options, and return the name if there is no trailing
+ // concatenated value: -oval
+ // Option: -o
+ // Value: val
+ if let Some(opt) = find_opt_by_short!(self, c) {
+ debugln!("Parser::parse_short_arg:iter:{}: Found valid opt", c);
+ self.settings.set(AS::ValidArgFound);
+ // Check for trailing concatenated value
+ let p: Vec<_> = arg.splitn(2, c).collect();
+ debugln!(
+ "Parser::parse_short_arg:iter:{}: p[0]={:?}, p[1]={:?}",
+ c,
+ p[0].as_bytes(),
+ p[1].as_bytes()
+ );
+ let i = p[0].as_bytes().len() + 1;
+ let val = if p[1].as_bytes().len() > 0 {
+ debugln!(
+ "Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii)",
+ c,
+ arg_os.split_at(i).1.as_bytes(),
+ arg_os.split_at(i).1
+ );
+ Some(arg_os.split_at(i).1)
+ } else {
+ None
+ };
+
+ // Default to "we're expecting a value later"
+ let ret = self.parse_opt(val, opt, false, matcher)?;
+
+ if self.cache.map_or(true, |name| name != opt.b.name) {
+ self.cache = Some(opt.b.name);
+ }
+
+ return Ok(ret);
+ } else if let Some(flag) = find_flag_by_short!(self, c) {
+ debugln!("Parser::parse_short_arg:iter:{}: Found valid flag", c);
+ self.settings.set(AS::ValidArgFound);
+ // Only flags can be help or version
+ self.check_for_help_and_version_char(c)?;
+ ret = self.parse_flag(flag, matcher)?;
+
+ // Handle conflicts, requirements, overrides, etc.
+ // Must be called here due to mutabililty
+ if self.cache.map_or(true, |name| name != flag.b.name) {
+ self.cache = Some(flag.b.name);
+ }
+ } else {
+ let arg = format!("-{}", c);
+ return Err(Error::unknown_argument(
+ &*arg,
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ }
+ Ok(ret)
+ }
+
+ fn parse_opt(
+ &self,
+ val: Option<&OsStr>,
+ opt: &OptBuilder<'a, 'b>,
+ had_eq: bool,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<ParseResult<'a>> {
+ debugln!("Parser::parse_opt; opt={}, val={:?}", opt.b.name, val);
+ debugln!("Parser::parse_opt; opt.settings={:?}", opt.b.settings);
+ let mut has_eq = false;
+ let no_val = val.is_none();
+ let empty_vals = opt.is_set(ArgSettings::EmptyValues);
+ let min_vals_zero = opt.v.min_vals.unwrap_or(1) == 0;
+ let needs_eq = opt.is_set(ArgSettings::RequireEquals);
+
+ debug!("Parser::parse_opt; Checking for val...");
+ if let Some(fv) = val {
+ has_eq = fv.starts_with(&[b'=']) || had_eq;
+ let v = fv.trim_left_matches(b'=');
+ if !empty_vals && (v.len() == 0 || (needs_eq && !has_eq)) {
+ sdebugln!("Found Empty - Error");
+ return Err(Error::empty_value(
+ opt,
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ sdebugln!("Found - {:?}, len: {}", v, v.len());
+ debugln!(
+ "Parser::parse_opt: {:?} contains '='...{:?}",
+ fv,
+ fv.starts_with(&[b'='])
+ );
+ self.add_val_to_arg(opt, v, matcher)?;
+ } else if needs_eq && !(empty_vals || min_vals_zero) {
+ sdebugln!("None, but requires equals...Error");
+ return Err(Error::empty_value(
+ opt,
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ } else {
+ sdebugln!("None");
+ }
+
+ matcher.inc_occurrence_of(opt.b.name);
+ // Increment or create the group "args"
+ self.groups_for_arg(opt.b.name)
+ .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+
+ let needs_delim = opt.is_set(ArgSettings::RequireDelimiter);
+ let mult = opt.is_set(ArgSettings::Multiple);
+ if no_val && min_vals_zero && !has_eq && needs_eq {
+ debugln!("Parser::parse_opt: More arg vals not required...");
+ return Ok(ParseResult::ValuesDone);
+ } else if no_val || (mult && !needs_delim) && !has_eq && matcher.needs_more_vals(opt) {
+ debugln!("Parser::parse_opt: More arg vals required...");
+ return Ok(ParseResult::Opt(opt.b.name));
+ }
+ debugln!("Parser::parse_opt: More arg vals not required...");
+ Ok(ParseResult::ValuesDone)
+ }
+
+ fn add_val_to_arg<A>(
+ &self,
+ arg: &A,
+ val: &OsStr,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<ParseResult<'a>>
+ where
+ A: AnyArg<'a, 'b> + Display,
+ {
+ debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name(), val);
+ debugln!(
+ "Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}",
+ self.is_set(AS::TrailingValues),
+ self.is_set(AS::DontDelimitTrailingValues)
+ );
+ if !(self.is_set(AS::TrailingValues) && self.is_set(AS::DontDelimitTrailingValues)) {
+ if let Some(delim) = arg.val_delim() {
+ if val.is_empty() {
+ Ok(self.add_single_val_to_arg(arg, val, matcher)?)
+ } else {
+ let mut iret = ParseResult::ValuesDone;
+ for v in val.split(delim as u32 as u8) {
+ iret = self.add_single_val_to_arg(arg, v, matcher)?;
+ }
+ // If there was a delimiter used, we're not looking for more values
+ if val.contains_byte(delim as u32 as u8)
+ || arg.is_set(ArgSettings::RequireDelimiter)
+ {
+ iret = ParseResult::ValuesDone;
+ }
+ Ok(iret)
+ }
+ } else {
+ self.add_single_val_to_arg(arg, val, matcher)
+ }
+ } else {
+ self.add_single_val_to_arg(arg, val, matcher)
+ }
+ }
+
+ fn add_single_val_to_arg<A>(
+ &self,
+ arg: &A,
+ v: &OsStr,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<ParseResult<'a>>
+ where
+ A: AnyArg<'a, 'b> + Display,
+ {
+ debugln!("Parser::add_single_val_to_arg;");
+ debugln!("Parser::add_single_val_to_arg: adding val...{:?}", v);
+
+ // update the current index because each value is a distinct index to clap
+ self.cur_idx.set(self.cur_idx.get() + 1);
+
+ // @TODO @docs @p4: docs for indices should probably note that a terminator isn't a value
+ // and therefore not reported in indices
+ if let Some(t) = arg.val_terminator() {
+ if t == v {
+ return Ok(ParseResult::ValuesDone);
+ }
+ }
+
+ matcher.add_val_to(arg.name(), v);
+ matcher.add_index_to(arg.name(), self.cur_idx.get());
+
+ // Increment or create the group "args"
+ if let Some(grps) = self.groups_for_arg(arg.name()) {
+ for grp in grps {
+ matcher.add_val_to(&*grp, v);
+ }
+ }
+
+ if matcher.needs_more_vals(arg) {
+ return Ok(ParseResult::Opt(arg.name()));
+ }
+ Ok(ParseResult::ValuesDone)
+ }
+
+ fn parse_flag(
+ &self,
+ flag: &FlagBuilder<'a, 'b>,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<ParseResult<'a>> {
+ debugln!("Parser::parse_flag;");
+
+ matcher.inc_occurrence_of(flag.b.name);
+ matcher.add_index_to(flag.b.name, self.cur_idx.get());
+
+ // Increment or create the group "args"
+ self.groups_for_arg(flag.b.name)
+ .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+
+ Ok(ParseResult::Flag)
+ }
+
+ fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>, args_rest: &[&str]) -> ClapResult<()> {
+ // Didn't match a flag or option
+ let suffix = suggestions::did_you_mean_flag_suffix(arg, &args_rest, longs!(self), &self.subcommands);
+
+ // Add the arg to the matches to build a proper usage string
+ if let Some(name) = suffix.1 {
+ if let Some(opt) = find_opt_by_long!(self, name) {
+ self.groups_for_arg(&*opt.b.name)
+ .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
+ matcher.insert(&*opt.b.name);
+ } else if let Some(flg) = find_flag_by_long!(self, name) {
+ self.groups_for_arg(&*flg.b.name)
+ .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
+ matcher.insert(&*flg.b.name);
+ }
+ }
+
+ let used_arg = format!("--{}", arg);
+ Err(Error::unknown_argument(
+ &*used_arg,
+ &*suffix.0,
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ))
+ }
+
+ // Prints the version to the user and exits if quit=true
+ fn print_version<W: Write>(&self, w: &mut W, use_long: bool) -> ClapResult<()> {
+ self.write_version(w, use_long)?;
+ w.flush().map_err(Error::from)
+ }
+
+ pub fn write_version<W: Write>(&self, w: &mut W, use_long: bool) -> io::Result<()> {
+ let ver = if use_long {
+ self.meta
+ .long_version
+ .unwrap_or_else(|| self.meta.version.unwrap_or(""))
+ } else {
+ self.meta
+ .version
+ .unwrap_or_else(|| self.meta.long_version.unwrap_or(""))
+ };
+ if let Some(bn) = self.meta.bin_name.as_ref() {
+ if bn.contains(' ') {
+ // Incase we're dealing with subcommands i.e. git mv is translated to git-mv
+ write!(w, "{} {}", bn.replace(" ", "-"), ver)
+ } else {
+ write!(w, "{} {}", &self.meta.name[..], ver)
+ }
+ } else {
+ write!(w, "{} {}", &self.meta.name[..], ver)
+ }
+ }
+
+ pub fn print_help(&self) -> ClapResult<()> {
+ let out = io::stdout();
+ let mut buf_w = BufWriter::new(out.lock());
+ self.write_help(&mut buf_w)
+ }
+
+ pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ Help::write_parser_help(w, self, false)
+ }
+
+ pub fn write_long_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ Help::write_parser_help(w, self, true)
+ }
+
+ pub fn write_help_err<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+ Help::write_parser_help_to_stderr(w, self)
+ }
+
+ pub fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
+ debugln!("Parser::add_defaults;");
+ macro_rules! add_val {
+ (@default $_self:ident, $a:ident, $m:ident) => {
+ if let Some(ref val) = $a.v.default_val {
+ debugln!("Parser::add_defaults:iter:{}: has default vals", $a.b.name);
+ if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) {
+ debugln!("Parser::add_defaults:iter:{}: has no user defined vals", $a.b.name);
+ $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
+
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ } else if $m.get($a.b.name).is_some() {
+ debugln!("Parser::add_defaults:iter:{}: has user defined vals", $a.b.name);
+ } else {
+ debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.b.name);
+
+ $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
+
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ }
+ } else {
+ debugln!("Parser::add_defaults:iter:{}: doesn't have default vals", $a.b.name);
+ }
+ };
+ ($_self:ident, $a:ident, $m:ident) => {
+ if let Some(ref vm) = $a.v.default_vals_ifs {
+ sdebugln!(" has conditional defaults");
+ let mut done = false;
+ if $m.get($a.b.name).is_none() {
+ for &(arg, val, default) in vm.values() {
+ let add = if let Some(a) = $m.get(arg) {
+ if let Some(v) = val {
+ a.vals.iter().any(|value| v == value)
+ } else {
+ true
+ }
+ } else {
+ false
+ };
+ if add {
+ $_self.add_val_to_arg($a, OsStr::new(default), $m)?;
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ done = true;
+ break;
+ }
+ }
+ }
+
+ if done {
+ continue; // outer loop (outside macro)
+ }
+ } else {
+ sdebugln!(" doesn't have conditional defaults");
+ }
+ add_val!(@default $_self, $a, $m)
+ };
+ }
+
+ for o in &self.opts {
+ debug!("Parser::add_defaults:iter:{}:", o.b.name);
+ add_val!(self, o, matcher);
+ }
+ for p in self.positionals.values() {
+ debug!("Parser::add_defaults:iter:{}:", p.b.name);
+ add_val!(self, p, matcher);
+ }
+ Ok(())
+ }
+
+ pub fn add_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
+ macro_rules! add_val {
+ ($_self:ident, $a:ident, $m:ident) => {
+ if let Some(ref val) = $a.v.env {
+ if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) {
+ if let Some(ref val) = val.1 {
+ $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
+
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ }
+ } else {
+ if let Some(ref val) = val.1 {
+ $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
+
+ if $_self.cache.map_or(true, |name| name != $a.name()) {
+ $_self.cache = Some($a.name());
+ }
+ }
+ }
+ }
+ };
+ }
+
+ for o in &self.opts {
+ add_val!(self, o, matcher);
+ }
+ for p in self.positionals.values() {
+ add_val!(self, p, matcher);
+ }
+ Ok(())
+ }
+
+ pub fn flags(&self) -> Iter<FlagBuilder<'a, 'b>> { self.flags.iter() }
+
+ pub fn opts(&self) -> Iter<OptBuilder<'a, 'b>> { self.opts.iter() }
+
+ pub fn positionals(&self) -> map::Values<PosBuilder<'a, 'b>> { self.positionals.values() }
+
+ pub fn subcommands(&self) -> Iter<App> { self.subcommands.iter() }
+
+ // Should we color the output? None=determined by output location, true=yes, false=no
+ #[doc(hidden)]
+ pub fn color(&self) -> ColorWhen {
+ debugln!("Parser::color;");
+ debug!("Parser::color: Color setting...");
+ if self.is_set(AS::ColorNever) {
+ sdebugln!("Never");
+ ColorWhen::Never
+ } else if self.is_set(AS::ColorAlways) {
+ sdebugln!("Always");
+ ColorWhen::Always
+ } else {
+ sdebugln!("Auto");
+ ColorWhen::Auto
+ }
+ }
+
+ pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg<'a, 'b>> {
+ if let Some(f) = find_by_name!(self, name, flags, iter) {
+ return Some(f);
+ }
+ if let Some(o) = find_by_name!(self, name, opts, iter) {
+ return Some(o);
+ }
+ if let Some(p) = find_by_name!(self, name, positionals, values) {
+ return Some(p);
+ }
+ None
+ }
+
+ /// Check is a given string matches the binary name for this parser
+ fn is_bin_name(&self, value: &str) -> bool {
+ self.meta
+ .bin_name
+ .as_ref()
+ .and_then(|name| Some(value == name))
+ .unwrap_or(false)
+ }
+
+ /// Check is a given string is an alias for this parser
+ fn is_alias(&self, value: &str) -> bool {
+ self.meta
+ .aliases
+ .as_ref()
+ .and_then(|aliases| {
+ for alias in aliases {
+ if alias.0 == value {
+ return Some(true);
+ }
+ }
+ Some(false)
+ })
+ .unwrap_or(false)
+ }
+
+ // Only used for completion scripts due to bin_name messiness
+ #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
+ pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
+ debugln!("Parser::find_subcommand: sc={}", sc);
+ debugln!(
+ "Parser::find_subcommand: Currently in Parser...{}",
+ self.meta.bin_name.as_ref().unwrap()
+ );
+ for s in &self.subcommands {
+ if s.p.is_bin_name(sc) {
+ return Some(s);
+ }
+ // XXX: why do we split here?
+ // isn't `sc` supposed to be single word already?
+ let last = sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG);
+ if s.p.is_alias(last) {
+ return Some(s);
+ }
+
+ if let Some(app) = s.p.find_subcommand(sc) {
+ return Some(app);
+ }
+ }
+ None
+ }
+
+ #[inline]
+ fn contains_long(&self, l: &str) -> bool { longs!(self).any(|al| al == &l) }
+
+ #[inline]
+ fn contains_short(&self, s: char) -> bool { shorts!(self).any(|arg_s| arg_s == &s) }
+}
diff --git a/clap/src/app/settings.rs b/clap/src/app/settings.rs
new file mode 100644
index 0000000..ec03997
--- /dev/null
+++ b/clap/src/app/settings.rs
@@ -0,0 +1,1174 @@
+// Std
+#[allow(deprecated, unused_imports)]
+use std::ascii::AsciiExt;
+use std::str::FromStr;
+use std::ops::BitOr;
+
+bitflags! {
+ struct Flags: u64 {
+ const SC_NEGATE_REQS = 1;
+ const SC_REQUIRED = 1 << 1;
+ const A_REQUIRED_ELSE_HELP = 1 << 2;
+ const GLOBAL_VERSION = 1 << 3;
+ const VERSIONLESS_SC = 1 << 4;
+ const UNIFIED_HELP = 1 << 5;
+ const WAIT_ON_ERROR = 1 << 6;
+ const SC_REQUIRED_ELSE_HELP= 1 << 7;
+ const NEEDS_LONG_HELP = 1 << 8;
+ const NEEDS_LONG_VERSION = 1 << 9;
+ const NEEDS_SC_HELP = 1 << 10;
+ const DISABLE_VERSION = 1 << 11;
+ const HIDDEN = 1 << 12;
+ const TRAILING_VARARG = 1 << 13;
+ const NO_BIN_NAME = 1 << 14;
+ const ALLOW_UNK_SC = 1 << 15;
+ const UTF8_STRICT = 1 << 16;
+ const UTF8_NONE = 1 << 17;
+ const LEADING_HYPHEN = 1 << 18;
+ const NO_POS_VALUES = 1 << 19;
+ const NEXT_LINE_HELP = 1 << 20;
+ const DERIVE_DISP_ORDER = 1 << 21;
+ const COLORED_HELP = 1 << 22;
+ const COLOR_ALWAYS = 1 << 23;
+ const COLOR_AUTO = 1 << 24;
+ const COLOR_NEVER = 1 << 25;
+ const DONT_DELIM_TRAIL = 1 << 26;
+ const ALLOW_NEG_NUMS = 1 << 27;
+ const LOW_INDEX_MUL_POS = 1 << 28;
+ const DISABLE_HELP_SC = 1 << 29;
+ const DONT_COLLAPSE_ARGS = 1 << 30;
+ const ARGS_NEGATE_SCS = 1 << 31;
+ const PROPAGATE_VALS_DOWN = 1 << 32;
+ const ALLOW_MISSING_POS = 1 << 33;
+ const TRAILING_VALUES = 1 << 34;
+ const VALID_NEG_NUM_FOUND = 1 << 35;
+ const PROPAGATED = 1 << 36;
+ const VALID_ARG_FOUND = 1 << 37;
+ const INFER_SUBCOMMANDS = 1 << 38;
+ const CONTAINS_LAST = 1 << 39;
+ const ARGS_OVERRIDE_SELF = 1 << 40;
+ const DISABLE_HELP_FLAGS = 1 << 41;
+ }
+}
+
+#[doc(hidden)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct AppFlags(Flags);
+
+impl BitOr for AppFlags {
+ type Output = Self;
+ fn bitor(self, rhs: Self) -> Self { AppFlags(self.0 | rhs.0) }
+}
+
+impl Default for AppFlags {
+ fn default() -> Self {
+ AppFlags(
+ Flags::NEEDS_LONG_VERSION | Flags::NEEDS_LONG_HELP | Flags::NEEDS_SC_HELP
+ | Flags::UTF8_NONE | Flags::COLOR_AUTO,
+ )
+ }
+}
+
+#[allow(deprecated)]
+impl AppFlags {
+ pub fn new() -> Self { AppFlags::default() }
+ pub fn zeroed() -> Self { AppFlags(Flags::empty()) }
+
+ impl_settings! { AppSettings,
+ ArgRequiredElseHelp => Flags::A_REQUIRED_ELSE_HELP,
+ ArgsNegateSubcommands => Flags::ARGS_NEGATE_SCS,
+ AllArgsOverrideSelf => Flags::ARGS_OVERRIDE_SELF,
+ AllowExternalSubcommands => Flags::ALLOW_UNK_SC,
+ AllowInvalidUtf8 => Flags::UTF8_NONE,
+ AllowLeadingHyphen => Flags::LEADING_HYPHEN,
+ AllowNegativeNumbers => Flags::ALLOW_NEG_NUMS,
+ AllowMissingPositional => Flags::ALLOW_MISSING_POS,
+ ColoredHelp => Flags::COLORED_HELP,
+ ColorAlways => Flags::COLOR_ALWAYS,
+ ColorAuto => Flags::COLOR_AUTO,
+ ColorNever => Flags::COLOR_NEVER,
+ DontDelimitTrailingValues => Flags::DONT_DELIM_TRAIL,
+ DontCollapseArgsInUsage => Flags::DONT_COLLAPSE_ARGS,
+ DeriveDisplayOrder => Flags::DERIVE_DISP_ORDER,
+ DisableHelpFlags => Flags::DISABLE_HELP_FLAGS,
+ DisableHelpSubcommand => Flags::DISABLE_HELP_SC,
+ DisableVersion => Flags::DISABLE_VERSION,
+ GlobalVersion => Flags::GLOBAL_VERSION,
+ HidePossibleValuesInHelp => Flags::NO_POS_VALUES,
+ Hidden => Flags::HIDDEN,
+ LowIndexMultiplePositional => Flags::LOW_INDEX_MUL_POS,
+ NeedsLongHelp => Flags::NEEDS_LONG_HELP,
+ NeedsLongVersion => Flags::NEEDS_LONG_VERSION,
+ NeedsSubcommandHelp => Flags::NEEDS_SC_HELP,
+ NoBinaryName => Flags::NO_BIN_NAME,
+ PropagateGlobalValuesDown=> Flags::PROPAGATE_VALS_DOWN,
+ StrictUtf8 => Flags::UTF8_STRICT,
+ SubcommandsNegateReqs => Flags::SC_NEGATE_REQS,
+ SubcommandRequired => Flags::SC_REQUIRED,
+ SubcommandRequiredElseHelp => Flags::SC_REQUIRED_ELSE_HELP,
+ TrailingVarArg => Flags::TRAILING_VARARG,
+ UnifiedHelpMessage => Flags::UNIFIED_HELP,
+ NextLineHelp => Flags::NEXT_LINE_HELP,
+ VersionlessSubcommands => Flags::VERSIONLESS_SC,
+ WaitOnError => Flags::WAIT_ON_ERROR,
+ TrailingValues => Flags::TRAILING_VALUES,
+ ValidNegNumFound => Flags::VALID_NEG_NUM_FOUND,
+ Propagated => Flags::PROPAGATED,
+ ValidArgFound => Flags::VALID_ARG_FOUND,
+ InferSubcommands => Flags::INFER_SUBCOMMANDS,
+ ContainsLast => Flags::CONTAINS_LAST
+ }
+}
+
+/// Application level settings, which affect how [`App`] operates
+///
+/// **NOTE:** When these settings are used, they apply only to current command, and are *not*
+/// propagated down or up through child or parent subcommands
+///
+/// [`App`]: ./struct.App.html
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum AppSettings {
+ /// Specifies that any invalid UTF-8 code points should *not* be treated as an error.
+ /// This is the default behavior of `clap`.
+ ///
+ /// **NOTE:** Using argument values with invalid UTF-8 code points requires using
+ /// [`ArgMatches::os_value_of`], [`ArgMatches::os_values_of`], [`ArgMatches::lossy_value_of`],
+ /// or [`ArgMatches::lossy_values_of`] for those particular arguments which may contain invalid
+ /// UTF-8 values
+ ///
+ /// **NOTE:** This rule only applies to argument values, as flags, options, and
+ /// [`SubCommand`]s themselves only allow valid UTF-8 code points.
+ ///
+ /// # Platform Specific
+ ///
+ /// Non Windows systems only
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```")]
+ /// # use clap::{App, AppSettings};
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::{OsStrExt,OsStringExt};
+ ///
+ /// let r = App::new("myprog")
+ /// //.setting(AppSettings::AllowInvalidUtf8)
+ /// .arg_from_usage("<arg> 'some positional arg'")
+ /// .get_matches_from_safe(
+ /// vec![
+ /// OsString::from("myprog"),
+ /// OsString::from_vec(vec![0xe9])]);
+ ///
+ /// assert!(r.is_ok());
+ /// let m = r.unwrap();
+ /// assert_eq!(m.value_of_os("arg").unwrap().as_bytes(), &[0xe9]);
+ /// ```
+ /// [`ArgMatches::os_value_of`]: ./struct.ArgMatches.html#method.os_value_of
+ /// [`ArgMatches::os_values_of`]: ./struct.ArgMatches.html#method.os_values_of
+ /// [`ArgMatches::lossy_value_of`]: ./struct.ArgMatches.html#method.lossy_value_of
+ /// [`ArgMatches::lossy_values_of`]: ./struct.ArgMatches.html#method.lossy_values_of
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ AllowInvalidUtf8,
+
+ /// Essentially sets [`Arg::overrides_with("itself")`] for all arguments.
+ ///
+ /// **WARNING:** Positional arguments cannot override themselves (or we would never be able
+ /// to advance to the next positional). This setting ignores positional arguments.
+ /// [`Arg::overrides_with("itself")`]: ./struct.Arg.html#method.overrides_with
+ AllArgsOverrideSelf,
+
+ /// Specifies that leading hyphens are allowed in argument *values*, such as negative numbers
+ /// like `-10`. (which would otherwise be parsed as another flag or option)
+ ///
+ /// **NOTE:** Use this setting with caution as it silences certain circumstances which would
+ /// otherwise be an error (such as accidentally forgetting to specify a value for leading
+ /// option). It is preferred to set this on a per argument basis, via [`Arg::allow_hyphen_values`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{Arg, App, AppSettings};
+ /// // Imagine you needed to represent negative numbers as well, such as -10
+ /// let m = App::new("nums")
+ /// .setting(AppSettings::AllowLeadingHyphen)
+ /// .arg(Arg::with_name("neg").index(1))
+ /// .get_matches_from(vec![
+ /// "nums", "-20"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("neg"), Some("-20"));
+ /// # ;
+ /// ```
+ /// [`Arg::allow_hyphen_values`]: ./struct.Arg.html#method.allow_hyphen_values
+ AllowLeadingHyphen,
+
+ /// Allows negative numbers to pass as values. This is similar to
+ /// `AllowLeadingHyphen` except that it only allows numbers, all
+ /// other undefined leading hyphens will fail to parse.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// let res = App::new("myprog")
+ /// .version("v1.1")
+ /// .setting(AppSettings::AllowNegativeNumbers)
+ /// .arg(Arg::with_name("num"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog", "-20"
+ /// ]);
+ /// assert!(res.is_ok());
+ /// let m = res.unwrap();
+ /// assert_eq!(m.value_of("num").unwrap(), "-20");
+ /// ```
+ /// [`AllowLeadingHyphen`]: ./enum.AppSettings.html#variant.AllowLeadingHyphen
+ AllowNegativeNumbers,
+
+ /// Allows one to implement two styles of CLIs where positionals can be used out of order.
+ ///
+ /// The first example is a CLI where the second to last positional argument is optional, but
+ /// the final positional argument is required. Such as `$ prog [optional] <required>` where one
+ /// of the two following usages is allowed:
+ ///
+ /// * `$ prog [optional] <required>`
+ /// * `$ prog <required>`
+ ///
+ /// This would otherwise not be allowed. This is useful when `[optional]` has a default value.
+ ///
+ /// **Note:** when using this style of "missing positionals" the final positional *must* be
+ /// [required] if `--` will not be used to skip to the final positional argument.
+ ///
+ /// **Note:** This style also only allows a single positional argument to be "skipped" without
+ /// the use of `--`. To skip more than one, see the second example.
+ ///
+ /// The second example is when one wants to skip multiple optional positional arguments, and use
+ /// of the `--` operator is OK (but not required if all arguments will be specified anyways).
+ ///
+ /// For example, imagine a CLI which has three positional arguments `[foo] [bar] [baz]...` where
+ /// `baz` accepts multiple values (similar to man `ARGS...` style training arguments).
+ ///
+ /// With this setting the following invocations are possible:
+ ///
+ /// * `$ prog foo bar baz1 baz2 baz3`
+ /// * `$ prog foo -- baz1 baz2 baz3`
+ /// * `$ prog -- baz1 baz2 baz3`
+ ///
+ /// # Examples
+ ///
+ /// Style number one from above:
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// // Assume there is an external subcommand named "subcmd"
+ /// let m = App::new("myprog")
+ /// .setting(AppSettings::AllowMissingPositional)
+ /// .arg(Arg::with_name("arg1"))
+ /// .arg(Arg::with_name("arg2")
+ /// .required(true))
+ /// .get_matches_from(vec![
+ /// "prog", "other"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("arg1"), None);
+ /// assert_eq!(m.value_of("arg2"), Some("other"));
+ /// ```
+ ///
+ /// Now the same example, but using a default value for the first optional positional argument
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// // Assume there is an external subcommand named "subcmd"
+ /// let m = App::new("myprog")
+ /// .setting(AppSettings::AllowMissingPositional)
+ /// .arg(Arg::with_name("arg1")
+ /// .default_value("something"))
+ /// .arg(Arg::with_name("arg2")
+ /// .required(true))
+ /// .get_matches_from(vec![
+ /// "prog", "other"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("arg1"), Some("something"));
+ /// assert_eq!(m.value_of("arg2"), Some("other"));
+ /// ```
+ /// Style number two from above:
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// // Assume there is an external subcommand named "subcmd"
+ /// let m = App::new("myprog")
+ /// .setting(AppSettings::AllowMissingPositional)
+ /// .arg(Arg::with_name("foo"))
+ /// .arg(Arg::with_name("bar"))
+ /// .arg(Arg::with_name("baz").multiple(true))
+ /// .get_matches_from(vec![
+ /// "prog", "foo", "bar", "baz1", "baz2", "baz3"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("foo"), Some("foo"));
+ /// assert_eq!(m.value_of("bar"), Some("bar"));
+ /// assert_eq!(m.values_of("baz").unwrap().collect::<Vec<_>>(), &["baz1", "baz2", "baz3"]);
+ /// ```
+ ///
+ /// Now notice if we don't specify `foo` or `baz` but use the `--` operator.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// // Assume there is an external subcommand named "subcmd"
+ /// let m = App::new("myprog")
+ /// .setting(AppSettings::AllowMissingPositional)
+ /// .arg(Arg::with_name("foo"))
+ /// .arg(Arg::with_name("bar"))
+ /// .arg(Arg::with_name("baz").multiple(true))
+ /// .get_matches_from(vec![
+ /// "prog", "--", "baz1", "baz2", "baz3"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("foo"), None);
+ /// assert_eq!(m.value_of("bar"), None);
+ /// assert_eq!(m.values_of("baz").unwrap().collect::<Vec<_>>(), &["baz1", "baz2", "baz3"]);
+ /// ```
+ /// [required]: ./struct.Arg.html#method.required
+ AllowMissingPositional,
+
+ /// Specifies that an unexpected positional argument,
+ /// which would otherwise cause a [`ErrorKind::UnknownArgument`] error,
+ /// should instead be treated as a [`SubCommand`] within the [`ArgMatches`] struct.
+ ///
+ /// **NOTE:** Use this setting with caution,
+ /// as a truly unexpected argument (i.e. one that is *NOT* an external subcommand)
+ /// will **not** cause an error and instead be treated as a potential subcommand.
+ /// One should check for such cases manually and inform the user appropriately.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings};
+ /// // Assume there is an external subcommand named "subcmd"
+ /// let m = App::new("myprog")
+ /// .setting(AppSettings::AllowExternalSubcommands)
+ /// .get_matches_from(vec![
+ /// "myprog", "subcmd", "--option", "value", "-fff", "--flag"
+ /// ]);
+ ///
+ /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty
+ /// // string argument name
+ /// match m.subcommand() {
+ /// (external, Some(ext_m)) => {
+ /// let ext_args: Vec<&str> = ext_m.values_of("").unwrap().collect();
+ /// assert_eq!(external, "subcmd");
+ /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
+ /// },
+ /// _ => {},
+ /// }
+ /// ```
+ /// [`ErrorKind::UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`ArgMatches`]: ./struct.ArgMatches.html
+ AllowExternalSubcommands,
+
+ /// Specifies that use of a valid [argument] negates [subcommands] being used after. By default
+ /// `clap` allows arguments between subcommands such as
+ /// `<cmd> [cmd_args] <cmd2> [cmd2_args] <cmd3> [cmd3_args]`. This setting disables that
+ /// functionality and says that arguments can only follow the *final* subcommand. For instance
+ /// using this setting makes only the following invocations possible:
+ ///
+ /// * `<cmd> <cmd2> <cmd3> [cmd3_args]`
+ /// * `<cmd> <cmd2> [cmd2_args]`
+ /// * `<cmd> [cmd_args]`
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::ArgsNegateSubcommands)
+ /// # ;
+ /// ```
+ /// [subcommands]: ./struct.SubCommand.html
+ /// [argument]: ./struct.Arg.html
+ ArgsNegateSubcommands,
+
+ /// Specifies that the help text should be displayed (and then exit gracefully),
+ /// if no arguments are present at runtime (i.e. an empty run such as, `$ myprog`.
+ ///
+ /// **NOTE:** [`SubCommand`]s count as arguments
+ ///
+ /// **NOTE:** Setting [`Arg::default_value`] effectively disables this option as it will
+ /// ensure that some argument is always present.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::ArgRequiredElseHelp)
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
+ ArgRequiredElseHelp,
+
+ /// Uses colorized help messages.
+ ///
+ /// **NOTE:** Must be compiled with the `color` cargo feature
+ ///
+ /// # Platform Specific
+ ///
+ /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms)
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::ColoredHelp)
+ /// .get_matches();
+ /// ```
+ ColoredHelp,
+
+ /// Enables colored output only when the output is going to a terminal or TTY.
+ ///
+ /// **NOTE:** This is the default behavior of `clap`.
+ ///
+ /// **NOTE:** Must be compiled with the `color` cargo feature.
+ ///
+ /// # Platform Specific
+ ///
+ /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::ColorAuto)
+ /// .get_matches();
+ /// ```
+ ColorAuto,
+
+ /// Enables colored output regardless of whether or not the output is going to a terminal/TTY.
+ ///
+ /// **NOTE:** Must be compiled with the `color` cargo feature.
+ ///
+ /// # Platform Specific
+ ///
+ /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::ColorAlways)
+ /// .get_matches();
+ /// ```
+ ColorAlways,
+
+ /// Disables colored output no matter if the output is going to a terminal/TTY, or not.
+ ///
+ /// **NOTE:** Must be compiled with the `color` cargo feature
+ ///
+ /// # Platform Specific
+ ///
+ /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms)
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::ColorNever)
+ /// .get_matches();
+ /// ```
+ ColorNever,
+
+ /// Disables the automatic collapsing of positional args into `[ARGS]` inside the usage string
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::DontCollapseArgsInUsage)
+ /// .get_matches();
+ /// ```
+ DontCollapseArgsInUsage,
+
+ /// Disables the automatic delimiting of values when `--` or [`AppSettings::TrailingVarArg`]
+ /// was used.
+ ///
+ /// **NOTE:** The same thing can be done manually by setting the final positional argument to
+ /// [`Arg::use_delimiter(false)`]. Using this setting is safer, because it's easier to locate
+ /// when making changes.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::DontDelimitTrailingValues)
+ /// .get_matches();
+ /// ```
+ /// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg
+ /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter
+ DontDelimitTrailingValues,
+
+ /// Disables `-h` and `--help` [`App`] without affecting any of the [`SubCommand`]s
+ /// (Defaults to `false`; application *does* have help flags)
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings, ErrorKind};
+ /// let res = App::new("myprog")
+ /// .setting(AppSettings::DisableHelpFlags)
+ /// .get_matches_from_safe(vec![
+ /// "myprog", "-h"
+ /// ]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, SubCommand, AppSettings, ErrorKind};
+ /// let res = App::new("myprog")
+ /// .setting(AppSettings::DisableHelpFlags)
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog", "test", "-h"
+ /// ]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::HelpDisplayed);
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`App`]: ./struct.App.html
+ DisableHelpFlags,
+
+ /// Disables the `help` subcommand
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings, ErrorKind, SubCommand};
+ /// let res = App::new("myprog")
+ /// .version("v1.1")
+ /// .setting(AppSettings::DisableHelpSubcommand)
+ /// // Normally, creating a subcommand causes a `help` subcommand to automatically
+ /// // be generated as well
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog", "help"
+ /// ]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ DisableHelpSubcommand,
+
+ /// Disables `-V` and `--version` [`App`] without affecting any of the [`SubCommand`]s
+ /// (Defaults to `false`; application *does* have a version flag)
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings, ErrorKind};
+ /// let res = App::new("myprog")
+ /// .version("v1.1")
+ /// .setting(AppSettings::DisableVersion)
+ /// .get_matches_from_safe(vec![
+ /// "myprog", "-V"
+ /// ]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, SubCommand, AppSettings, ErrorKind};
+ /// let res = App::new("myprog")
+ /// .version("v1.1")
+ /// .setting(AppSettings::DisableVersion)
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog", "test", "-V"
+ /// ]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::VersionDisplayed);
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`App`]: ./struct.App.html
+ DisableVersion,
+
+ /// Displays the arguments and [`SubCommand`]s in the help message in the order that they were
+ /// declared in, and not alphabetically which is the default.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::DeriveDisplayOrder)
+ /// .get_matches();
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ DeriveDisplayOrder,
+
+ /// Specifies to use the version of the current command for all child [`SubCommand`]s.
+ /// (Defaults to `false`; subcommands have independent version strings from their parents.)
+ ///
+ /// **NOTE:** The version for the current command **and** this setting must be set **prior** to
+ /// adding any child subcommands
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .version("v1.1")
+ /// .setting(AppSettings::GlobalVersion)
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches();
+ /// // running `$ myprog test --version` will display
+ /// // "myprog-test v1.1"
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ GlobalVersion,
+
+ /// Specifies that this [`SubCommand`] should be hidden from help messages
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings, SubCommand};
+ /// App::new("myprog")
+ /// .subcommand(SubCommand::with_name("test")
+ /// .setting(AppSettings::Hidden))
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ Hidden,
+
+ /// Tells `clap` *not* to print possible values when displaying help information.
+ /// This can be useful if there are many values, or they are explained elsewhere.
+ HidePossibleValuesInHelp,
+
+ /// Tries to match unknown args to partial [`subcommands`] or their [aliases]. For example to
+ /// match a subcommand named `test`, one could use `t`, `te`, `tes`, and `test`.
+ ///
+ /// **NOTE:** The match *must not* be ambiguous at all in order to succeed. i.e. to match `te`
+ /// to `test` there could not also be a subcommand or alias `temp` because both start with `te`
+ ///
+ /// **CAUTION:** This setting can interfere with [positional/free arguments], take care when
+ /// designing CLIs which allow inferred subcommands and have potential positional/free
+ /// arguments whose values could start with the same characters as subcommands. If this is the
+ /// case, it's recommended to use settings such as [`AppSeettings::ArgsNegateSubcommands`] in
+ /// conjunction with this setting.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// let m = App::new("prog")
+ /// .setting(AppSettings::InferSubcommands)
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from(vec![
+ /// "prog", "te"
+ /// ]);
+ /// assert_eq!(m.subcommand_name(), Some("test"));
+ /// ```
+ /// [`subcommands`]: ./struct.SubCommand.html
+ /// [positional/free arguments]: ./struct.Arg.html#method.index
+ /// [aliases]: ./struct.App.html#method.alias
+ /// [`AppSeettings::ArgsNegateSubcommands`]: ./enum.AppSettings.html#variant.ArgsNegateSubcommands
+ InferSubcommands,
+
+ /// Specifies that the parser should not assume the first argument passed is the binary name.
+ /// This is normally the case when using a "daemon" style mode, or an interactive CLI where one
+ /// one would not normally type the binary or program name for each command.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// let m = App::new("myprog")
+ /// .setting(AppSettings::NoBinaryName)
+ /// .arg(Arg::from_usage("<cmd>... 'commands to run'"))
+ /// .get_matches_from(vec!["command", "set"]);
+ ///
+ /// let cmds: Vec<&str> = m.values_of("cmd").unwrap().collect();
+ /// assert_eq!(cmds, ["command", "set"]);
+ /// ```
+ NoBinaryName,
+
+ /// Places the help string for all arguments on the line after the argument.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::NextLineHelp)
+ /// .get_matches();
+ /// ```
+ NextLineHelp,
+
+ /// **DEPRECATED**: This setting is no longer required in order to propagate values up or down
+ ///
+ /// Specifies that the parser should propagate global arg's values down or up through any *used*
+ /// child subcommands. Meaning, if a subcommand wasn't used, the values won't be propagated to
+ /// said subcommand.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings, SubCommand};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::from_usage("[cmd] 'command to run'")
+ /// .global(true))
+ /// .subcommand(SubCommand::with_name("foo"))
+ /// .get_matches_from(vec!["myprog", "set", "foo"]);
+ ///
+ /// assert_eq!(m.value_of("cmd"), Some("set"));
+ ///
+ /// let sub_m = m.subcommand_matches("foo").unwrap();
+ /// assert_eq!(sub_m.value_of("cmd"), Some("set"));
+ /// ```
+ /// Now doing the same thing, but *not* using any subcommands will result in the value not being
+ /// propagated down.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings, SubCommand};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::from_usage("[cmd] 'command to run'")
+ /// .global(true))
+ /// .subcommand(SubCommand::with_name("foo"))
+ /// .get_matches_from(vec!["myprog", "set"]);
+ ///
+ /// assert_eq!(m.value_of("cmd"), Some("set"));
+ ///
+ /// assert!(m.subcommand_matches("foo").is_none());
+ /// ```
+ #[deprecated(since = "2.27.0", note = "No longer required to propagate values")]
+ PropagateGlobalValuesDown,
+
+ /// Allows [`SubCommand`]s to override all requirements of the parent command.
+ /// For example if you had a subcommand or top level application with a required argument
+ /// that is only required as long as there is no subcommand present,
+ /// using this setting would allow you to set those arguments to [`Arg::required(true)`]
+ /// and yet receive no error so long as the user uses a valid subcommand instead.
+ ///
+ /// **NOTE:** This defaults to false (using subcommand does *not* negate requirements)
+ ///
+ /// # Examples
+ ///
+ /// This first example shows that it is an error to not use a required argument
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind};
+ /// let err = App::new("myprog")
+ /// .setting(AppSettings::SubcommandsNegateReqs)
+ /// .arg(Arg::with_name("opt").required(true))
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog"
+ /// ]);
+ /// assert!(err.is_err());
+ /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// # ;
+ /// ```
+ ///
+ /// This next example shows that it is no longer error to not use a required argument if a
+ /// valid subcommand is used.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind};
+ /// let noerr = App::new("myprog")
+ /// .setting(AppSettings::SubcommandsNegateReqs)
+ /// .arg(Arg::with_name("opt").required(true))
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog", "test"
+ /// ]);
+ /// assert!(noerr.is_ok());
+ /// # ;
+ /// ```
+ /// [`Arg::required(true)`]: ./struct.Arg.html#method.required
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ SubcommandsNegateReqs,
+
+ /// Specifies that the help text should be displayed (before exiting gracefully) if no
+ /// [`SubCommand`]s are present at runtime (i.e. an empty run such as `$ myprog`).
+ ///
+ /// **NOTE:** This should *not* be used with [`AppSettings::SubcommandRequired`] as they do
+ /// nearly same thing; this prints the help text, and the other prints an error.
+ ///
+ /// **NOTE:** If the user specifies arguments at runtime, but no subcommand the help text will
+ /// still be displayed and exit. If this is *not* the desired result, consider using
+ /// [`AppSettings::ArgRequiredElseHelp`] instead.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::SubcommandRequiredElseHelp)
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired
+ /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp
+ SubcommandRequiredElseHelp,
+
+ /// Specifies that any invalid UTF-8 code points should be treated as an error and fail
+ /// with a [`ErrorKind::InvalidUtf8`] error.
+ ///
+ /// **NOTE:** This rule only applies to argument values; Things such as flags, options, and
+ /// [`SubCommand`]s themselves only allow valid UTF-8 code points.
+ ///
+ /// # Platform Specific
+ ///
+ /// Non Windows systems only
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```")]
+ /// # use clap::{App, AppSettings, ErrorKind};
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::OsStringExt;
+ ///
+ /// let m = App::new("myprog")
+ /// .setting(AppSettings::StrictUtf8)
+ /// .arg_from_usage("<arg> 'some positional arg'")
+ /// .get_matches_from_safe(
+ /// vec![
+ /// OsString::from("myprog"),
+ /// OsString::from_vec(vec![0xe9])]);
+ ///
+ /// assert!(m.is_err());
+ /// assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`ErrorKind::InvalidUtf8`]: ./enum.ErrorKind.html#variant.InvalidUtf8
+ StrictUtf8,
+
+ /// Allows specifying that if no [`SubCommand`] is present at runtime,
+ /// error and exit gracefully.
+ ///
+ /// **NOTE:** This defaults to `false` (subcommands do *not* need to be present)
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings, SubCommand, ErrorKind};
+ /// let err = App::new("myprog")
+ /// .setting(AppSettings::SubcommandRequired)
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog",
+ /// ]);
+ /// assert!(err.is_err());
+ /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand);
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ SubcommandRequired,
+
+ /// Specifies that the final positional argument is a "VarArg" and that `clap` should not
+ /// attempt to parse any further args.
+ ///
+ /// The values of the trailing positional argument will contain all args from itself on.
+ ///
+ /// **NOTE:** The final positional argument **must** have [`Arg::multiple(true)`] or the usage
+ /// string equivalent.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// let m = App::new("myprog")
+ /// .setting(AppSettings::TrailingVarArg)
+ /// .arg(Arg::from_usage("<cmd>... 'commands to run'"))
+ /// .get_matches_from(vec!["myprog", "arg1", "-r", "val1"]);
+ ///
+ /// let trail: Vec<&str> = m.values_of("cmd").unwrap().collect();
+ /// assert_eq!(trail, ["arg1", "-r", "val1"]);
+ /// ```
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ TrailingVarArg,
+
+ /// Groups flags and options together, presenting a more unified help message
+ /// (a la `getopts` or `docopt` style).
+ ///
+ /// The default is that the auto-generated help message will group flags, and options
+ /// separately.
+ ///
+ /// **NOTE:** This setting is cosmetic only and does not affect any functionality.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::UnifiedHelpMessage)
+ /// .get_matches();
+ /// // running `myprog --help` will display a unified "docopt" or "getopts" style help message
+ /// ```
+ UnifiedHelpMessage,
+
+ /// Disables `-V` and `--version` for all [`SubCommand`]s
+ /// (Defaults to `false`; subcommands *do* have version flags.)
+ ///
+ /// **NOTE:** This setting must be set **prior** to adding any subcommands.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, SubCommand, AppSettings, ErrorKind};
+ /// let res = App::new("myprog")
+ /// .version("v1.1")
+ /// .setting(AppSettings::VersionlessSubcommands)
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog", "test", "-V"
+ /// ]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ VersionlessSubcommands,
+
+ /// Will display a message "Press \[ENTER\]/\[RETURN\] to continue..." and wait for user before
+ /// exiting
+ ///
+ /// This is most useful when writing an application which is run from a GUI shortcut, or on
+ /// Windows where a user tries to open the binary by double-clicking instead of using the
+ /// command line.
+ ///
+ /// **NOTE:** This setting is **not** recursive with [`SubCommand`]s, meaning if you wish this
+ /// behavior for all subcommands, you must set this on each command (needing this is extremely
+ /// rare)
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings};
+ /// App::new("myprog")
+ /// .setting(AppSettings::WaitOnError)
+ /// # ;
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ WaitOnError,
+
+ #[doc(hidden)] NeedsLongVersion,
+
+ #[doc(hidden)] NeedsLongHelp,
+
+ #[doc(hidden)] NeedsSubcommandHelp,
+
+ #[doc(hidden)] LowIndexMultiplePositional,
+
+ #[doc(hidden)] TrailingValues,
+
+ #[doc(hidden)] ValidNegNumFound,
+
+ #[doc(hidden)] Propagated,
+
+ #[doc(hidden)] ValidArgFound,
+
+ #[doc(hidden)] ContainsLast,
+}
+
+impl FromStr for AppSettings {
+ type Err = String;
+ fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
+ match &*s.to_ascii_lowercase() {
+ "disablehelpflags" => Ok(AppSettings::DisableHelpFlags),
+ "argrequiredelsehelp" => Ok(AppSettings::ArgRequiredElseHelp),
+ "argsnegatesubcommands" => Ok(AppSettings::ArgsNegateSubcommands),
+ "allowinvalidutf8" => Ok(AppSettings::AllowInvalidUtf8),
+ "allowleadinghyphen" => Ok(AppSettings::AllowLeadingHyphen),
+ "allowexternalsubcommands" => Ok(AppSettings::AllowExternalSubcommands),
+ "allownegativenumbers" => Ok(AppSettings::AllowNegativeNumbers),
+ "colorauto" => Ok(AppSettings::ColorAuto),
+ "coloralways" => Ok(AppSettings::ColorAlways),
+ "colornever" => Ok(AppSettings::ColorNever),
+ "coloredhelp" => Ok(AppSettings::ColoredHelp),
+ "derivedisplayorder" => Ok(AppSettings::DeriveDisplayOrder),
+ "dontcollapseargsinusage" => Ok(AppSettings::DontCollapseArgsInUsage),
+ "dontdelimittrailingvalues" => Ok(AppSettings::DontDelimitTrailingValues),
+ "disablehelpsubcommand" => Ok(AppSettings::DisableHelpSubcommand),
+ "disableversion" => Ok(AppSettings::DisableVersion),
+ "globalversion" => Ok(AppSettings::GlobalVersion),
+ "hidden" => Ok(AppSettings::Hidden),
+ "hidepossiblevaluesinhelp" => Ok(AppSettings::HidePossibleValuesInHelp),
+ "infersubcommands" => Ok(AppSettings::InferSubcommands),
+ "lowindexmultiplepositional" => Ok(AppSettings::LowIndexMultiplePositional),
+ "nobinaryname" => Ok(AppSettings::NoBinaryName),
+ "nextlinehelp" => Ok(AppSettings::NextLineHelp),
+ "strictutf8" => Ok(AppSettings::StrictUtf8),
+ "subcommandsnegatereqs" => Ok(AppSettings::SubcommandsNegateReqs),
+ "subcommandrequired" => Ok(AppSettings::SubcommandRequired),
+ "subcommandrequiredelsehelp" => Ok(AppSettings::SubcommandRequiredElseHelp),
+ "trailingvararg" => Ok(AppSettings::TrailingVarArg),
+ "unifiedhelpmessage" => Ok(AppSettings::UnifiedHelpMessage),
+ "versionlesssubcommands" => Ok(AppSettings::VersionlessSubcommands),
+ "waitonerror" => Ok(AppSettings::WaitOnError),
+ "validnegnumfound" => Ok(AppSettings::ValidNegNumFound),
+ "validargfound" => Ok(AppSettings::ValidArgFound),
+ "propagated" => Ok(AppSettings::Propagated),
+ "trailingvalues" => Ok(AppSettings::TrailingValues),
+ _ => Err("unknown AppSetting, cannot convert from str".to_owned()),
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::AppSettings;
+
+ #[test]
+ fn app_settings_fromstr() {
+ assert_eq!(
+ "disablehelpflags".parse::<AppSettings>().unwrap(),
+ AppSettings::DisableHelpFlags
+ );
+ assert_eq!(
+ "argsnegatesubcommands".parse::<AppSettings>().unwrap(),
+ AppSettings::ArgsNegateSubcommands
+ );
+ assert_eq!(
+ "argrequiredelsehelp".parse::<AppSettings>().unwrap(),
+ AppSettings::ArgRequiredElseHelp
+ );
+ assert_eq!(
+ "allowexternalsubcommands".parse::<AppSettings>().unwrap(),
+ AppSettings::AllowExternalSubcommands
+ );
+ assert_eq!(
+ "allowinvalidutf8".parse::<AppSettings>().unwrap(),
+ AppSettings::AllowInvalidUtf8
+ );
+ assert_eq!(
+ "allowleadinghyphen".parse::<AppSettings>().unwrap(),
+ AppSettings::AllowLeadingHyphen
+ );
+ assert_eq!(
+ "allownegativenumbers".parse::<AppSettings>().unwrap(),
+ AppSettings::AllowNegativeNumbers
+ );
+ assert_eq!(
+ "coloredhelp".parse::<AppSettings>().unwrap(),
+ AppSettings::ColoredHelp
+ );
+ assert_eq!(
+ "colorauto".parse::<AppSettings>().unwrap(),
+ AppSettings::ColorAuto
+ );
+ assert_eq!(
+ "coloralways".parse::<AppSettings>().unwrap(),
+ AppSettings::ColorAlways
+ );
+ assert_eq!(
+ "colornever".parse::<AppSettings>().unwrap(),
+ AppSettings::ColorNever
+ );
+ assert_eq!(
+ "disablehelpsubcommand".parse::<AppSettings>().unwrap(),
+ AppSettings::DisableHelpSubcommand
+ );
+ assert_eq!(
+ "disableversion".parse::<AppSettings>().unwrap(),
+ AppSettings::DisableVersion
+ );
+ assert_eq!(
+ "dontcollapseargsinusage".parse::<AppSettings>().unwrap(),
+ AppSettings::DontCollapseArgsInUsage
+ );
+ assert_eq!(
+ "dontdelimittrailingvalues".parse::<AppSettings>().unwrap(),
+ AppSettings::DontDelimitTrailingValues
+ );
+ assert_eq!(
+ "derivedisplayorder".parse::<AppSettings>().unwrap(),
+ AppSettings::DeriveDisplayOrder
+ );
+ assert_eq!(
+ "globalversion".parse::<AppSettings>().unwrap(),
+ AppSettings::GlobalVersion
+ );
+ assert_eq!(
+ "hidden".parse::<AppSettings>().unwrap(),
+ AppSettings::Hidden
+ );
+ assert_eq!(
+ "hidepossiblevaluesinhelp".parse::<AppSettings>().unwrap(),
+ AppSettings::HidePossibleValuesInHelp
+ );
+ assert_eq!(
+ "lowindexmultiplePositional".parse::<AppSettings>().unwrap(),
+ AppSettings::LowIndexMultiplePositional
+ );
+ assert_eq!(
+ "nobinaryname".parse::<AppSettings>().unwrap(),
+ AppSettings::NoBinaryName
+ );
+ assert_eq!(
+ "nextlinehelp".parse::<AppSettings>().unwrap(),
+ AppSettings::NextLineHelp
+ );
+ assert_eq!(
+ "subcommandsnegatereqs".parse::<AppSettings>().unwrap(),
+ AppSettings::SubcommandsNegateReqs
+ );
+ assert_eq!(
+ "subcommandrequired".parse::<AppSettings>().unwrap(),
+ AppSettings::SubcommandRequired
+ );
+ assert_eq!(
+ "subcommandrequiredelsehelp".parse::<AppSettings>().unwrap(),
+ AppSettings::SubcommandRequiredElseHelp
+ );
+ assert_eq!(
+ "strictutf8".parse::<AppSettings>().unwrap(),
+ AppSettings::StrictUtf8
+ );
+ assert_eq!(
+ "trailingvararg".parse::<AppSettings>().unwrap(),
+ AppSettings::TrailingVarArg
+ );
+ assert_eq!(
+ "unifiedhelpmessage".parse::<AppSettings>().unwrap(),
+ AppSettings::UnifiedHelpMessage
+ );
+ assert_eq!(
+ "versionlesssubcommands".parse::<AppSettings>().unwrap(),
+ AppSettings::VersionlessSubcommands
+ );
+ assert_eq!(
+ "waitonerror".parse::<AppSettings>().unwrap(),
+ AppSettings::WaitOnError
+ );
+ assert_eq!(
+ "validnegnumfound".parse::<AppSettings>().unwrap(),
+ AppSettings::ValidNegNumFound
+ );
+ assert_eq!(
+ "validargfound".parse::<AppSettings>().unwrap(),
+ AppSettings::ValidArgFound
+ );
+ assert_eq!(
+ "propagated".parse::<AppSettings>().unwrap(),
+ AppSettings::Propagated
+ );
+ assert_eq!(
+ "trailingvalues".parse::<AppSettings>().unwrap(),
+ AppSettings::TrailingValues
+ );
+ assert_eq!(
+ "infersubcommands".parse::<AppSettings>().unwrap(),
+ AppSettings::InferSubcommands
+ );
+ assert!("hahahaha".parse::<AppSettings>().is_err());
+ }
+}
diff --git a/clap/src/app/usage.rs b/clap/src/app/usage.rs
new file mode 100644
index 0000000..6090588
--- /dev/null
+++ b/clap/src/app/usage.rs
@@ -0,0 +1,479 @@
+// std
+use std::collections::{BTreeMap, VecDeque};
+
+// Internal
+use INTERNAL_ERROR_MSG;
+use args::{AnyArg, ArgMatcher, PosBuilder};
+use args::settings::ArgSettings;
+use app::settings::AppSettings as AS;
+use app::parser::Parser;
+
+// Creates a usage string for display. This happens just after all arguments were parsed, but before
+// any subcommands have been parsed (so as to give subcommands their own usage recursively)
+pub fn create_usage_with_title(p: &Parser, used: &[&str]) -> String {
+ debugln!("usage::create_usage_with_title;");
+ let mut usage = String::with_capacity(75);
+ usage.push_str("USAGE:\n ");
+ usage.push_str(&*create_usage_no_title(p, used));
+ usage
+}
+
+// Creates a usage string to be used in error message (i.e. one with currently used args)
+pub fn create_error_usage<'a, 'b>(
+ p: &Parser<'a, 'b>,
+ matcher: &'b ArgMatcher<'a>,
+ extra: Option<&str>,
+) -> String {
+ let mut args: Vec<_> = matcher
+ .arg_names()
+ .iter()
+ .filter(|n| {
+ if let Some(o) = find_by_name!(p, **n, opts, iter) {
+ !o.b.is_set(ArgSettings::Required) && !o.b.is_set(ArgSettings::Hidden)
+ } else if let Some(p) = find_by_name!(p, **n, positionals, values) {
+ !p.b.is_set(ArgSettings::Required) && p.b.is_set(ArgSettings::Hidden)
+ } else {
+ true // flags can't be required, so they're always true
+ }
+ })
+ .map(|&n| n)
+ .collect();
+ if let Some(r) = extra {
+ args.push(r);
+ }
+ create_usage_with_title(p, &*args)
+}
+
+// Creates a usage string (*without title*) if one was not provided by the user manually.
+pub fn create_usage_no_title(p: &Parser, used: &[&str]) -> String {
+ debugln!("usage::create_usage_no_title;");
+ if let Some(u) = p.meta.usage_str {
+ String::from(&*u)
+ } else if used.is_empty() {
+ create_help_usage(p, true)
+ } else {
+ create_smart_usage(p, used)
+ }
+}
+
+// Creates a usage string for display in help messages (i.e. not for errors)
+pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String {
+ let mut usage = String::with_capacity(75);
+ let name = p.meta
+ .usage
+ .as_ref()
+ .unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name));
+ usage.push_str(&*name);
+ let req_string = if incl_reqs {
+ let mut reqs: Vec<&str> = p.required().map(|r| &**r).collect();
+ reqs.sort();
+ reqs.dedup();
+ get_required_usage_from(p, &reqs, None, None, false)
+ .iter()
+ .fold(String::new(), |a, s| a + &format!(" {}", s)[..])
+ } else {
+ String::new()
+ };
+
+ let flags = needs_flags_tag(p);
+ if flags && !p.is_set(AS::UnifiedHelpMessage) {
+ usage.push_str(" [FLAGS]");
+ } else if flags {
+ usage.push_str(" [OPTIONS]");
+ }
+ if !p.is_set(AS::UnifiedHelpMessage) && p.opts.iter().any(|o| {
+ !o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)
+ }) {
+ usage.push_str(" [OPTIONS]");
+ }
+
+ usage.push_str(&req_string[..]);
+
+ let has_last = p.positionals.values().any(|p| p.is_set(ArgSettings::Last));
+ // places a '--' in the usage string if there are args and options
+ // supporting multiple values
+ if p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple))
+ && p.positionals
+ .values()
+ .any(|p| !p.is_set(ArgSettings::Required))
+ && !(p.has_visible_subcommands() || p.is_set(AS::AllowExternalSubcommands))
+ && !has_last
+ {
+ usage.push_str(" [--]");
+ }
+ let not_req_or_hidden = |p: &PosBuilder| {
+ (!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last))
+ && !p.is_set(ArgSettings::Hidden)
+ };
+ if p.has_positionals() && p.positionals.values().any(not_req_or_hidden) {
+ if let Some(args_tag) = get_args_tag(p, incl_reqs) {
+ usage.push_str(&*args_tag);
+ } else {
+ usage.push_str(" [ARGS]");
+ }
+ if has_last && incl_reqs {
+ let pos = p.positionals
+ .values()
+ .find(|p| p.b.is_set(ArgSettings::Last))
+ .expect(INTERNAL_ERROR_MSG);
+ debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name());
+ let req = pos.is_set(ArgSettings::Required);
+ if req
+ && p.positionals
+ .values()
+ .any(|p| !p.is_set(ArgSettings::Required))
+ {
+ usage.push_str(" -- <");
+ } else if req {
+ usage.push_str(" [--] <");
+ } else {
+ usage.push_str(" [-- <");
+ }
+ usage.push_str(&*pos.name_no_brackets());
+ usage.push_str(">");
+ usage.push_str(pos.multiple_str());
+ if !req {
+ usage.push_str("]");
+ }
+ }
+ }
+
+ // incl_reqs is only false when this function is called recursively
+ if p.has_visible_subcommands() && incl_reqs || p.is_set(AS::AllowExternalSubcommands) {
+ if p.is_set(AS::SubcommandsNegateReqs) || p.is_set(AS::ArgsNegateSubcommands) {
+ if !p.is_set(AS::ArgsNegateSubcommands) {
+ usage.push_str("\n ");
+ usage.push_str(&*create_help_usage(p, false));
+ usage.push_str(" <SUBCOMMAND>");
+ } else {
+ usage.push_str("\n ");
+ usage.push_str(&*name);
+ usage.push_str(" <SUBCOMMAND>");
+ }
+ } else if p.is_set(AS::SubcommandRequired) || p.is_set(AS::SubcommandRequiredElseHelp) {
+ usage.push_str(" <SUBCOMMAND>");
+ } else {
+ usage.push_str(" [SUBCOMMAND]");
+ }
+ }
+ usage.shrink_to_fit();
+ debugln!("usage::create_help_usage: usage={}", usage);
+ usage
+}
+
+// Creates a context aware usage string, or "smart usage" from currently used
+// args, and requirements
+fn create_smart_usage(p: &Parser, used: &[&str]) -> String {
+ debugln!("usage::smart_usage;");
+ let mut usage = String::with_capacity(75);
+ let mut hs: Vec<&str> = p.required().map(|s| &**s).collect();
+ hs.extend_from_slice(used);
+
+ let r_string = get_required_usage_from(p, &hs, None, None, false)
+ .iter()
+ .fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
+
+ usage.push_str(
+ &p.meta
+ .usage
+ .as_ref()
+ .unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name))[..],
+ );
+ usage.push_str(&*r_string);
+ if p.is_set(AS::SubcommandRequired) {
+ usage.push_str(" <SUBCOMMAND>");
+ }
+ usage.shrink_to_fit();
+ usage
+}
+
+// Gets the `[ARGS]` tag for the usage string
+fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option<String> {
+ debugln!("usage::get_args_tag;");
+ let mut count = 0;
+ 'outer: for pos in p.positionals
+ .values()
+ .filter(|pos| !pos.is_set(ArgSettings::Required))
+ .filter(|pos| !pos.is_set(ArgSettings::Hidden))
+ .filter(|pos| !pos.is_set(ArgSettings::Last))
+ {
+ debugln!("usage::get_args_tag:iter:{}:", pos.b.name);
+ if let Some(g_vec) = p.groups_for_arg(pos.b.name) {
+ for grp_s in &g_vec {
+ debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.b.name, grp_s);
+ // if it's part of a required group we don't want to count it
+ if p.groups.iter().any(|g| g.required && (&g.name == grp_s)) {
+ continue 'outer;
+ }
+ }
+ }
+ count += 1;
+ debugln!(
+ "usage::get_args_tag:iter: {} Args not required or hidden",
+ count
+ );
+ }
+ if !p.is_set(AS::DontCollapseArgsInUsage) && count > 1 {
+ debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]");
+ return None; // [ARGS]
+ } else if count == 1 && incl_reqs {
+ let pos = p.positionals
+ .values()
+ .find(|pos| {
+ !pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden)
+ && !pos.is_set(ArgSettings::Last)
+ })
+ .expect(INTERNAL_ERROR_MSG);
+ debugln!(
+ "usage::get_args_tag:iter: Exactly one, returning '{}'",
+ pos.name()
+ );
+ return Some(format!(
+ " [{}]{}",
+ pos.name_no_brackets(),
+ pos.multiple_str()
+ ));
+ } else if p.is_set(AS::DontCollapseArgsInUsage) && !p.positionals.is_empty() && incl_reqs {
+ debugln!("usage::get_args_tag:iter: Don't collapse returning all");
+ return Some(
+ p.positionals
+ .values()
+ .filter(|pos| !pos.is_set(ArgSettings::Required))
+ .filter(|pos| !pos.is_set(ArgSettings::Hidden))
+ .filter(|pos| !pos.is_set(ArgSettings::Last))
+ .map(|pos| {
+ format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
+ })
+ .collect::<Vec<_>>()
+ .join(""),
+ );
+ } else if !incl_reqs {
+ debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string");
+ let highest_req_pos = p.positionals
+ .iter()
+ .filter_map(|(idx, pos)| {
+ if pos.b.is_set(ArgSettings::Required) && !pos.b.is_set(ArgSettings::Last) {
+ Some(idx)
+ } else {
+ None
+ }
+ })
+ .max()
+ .unwrap_or_else(|| p.positionals.len());
+ return Some(
+ p.positionals
+ .iter()
+ .filter_map(|(idx, pos)| {
+ if idx <= highest_req_pos {
+ Some(pos)
+ } else {
+ None
+ }
+ })
+ .filter(|pos| !pos.is_set(ArgSettings::Required))
+ .filter(|pos| !pos.is_set(ArgSettings::Hidden))
+ .filter(|pos| !pos.is_set(ArgSettings::Last))
+ .map(|pos| {
+ format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
+ })
+ .collect::<Vec<_>>()
+ .join(""),
+ );
+ }
+ Some("".into())
+}
+
+// Determines if we need the `[FLAGS]` tag in the usage string
+fn needs_flags_tag(p: &Parser) -> bool {
+ debugln!("usage::needs_flags_tag;");
+ 'outer: for f in &p.flags {
+ debugln!("usage::needs_flags_tag:iter: f={};", f.b.name);
+ if let Some(l) = f.s.long {
+ if l == "help" || l == "version" {
+ // Don't print `[FLAGS]` just for help or version
+ continue;
+ }
+ }
+ if let Some(g_vec) = p.groups_for_arg(f.b.name) {
+ for grp_s in &g_vec {
+ debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s);
+ if p.groups.iter().any(|g| &g.name == grp_s && g.required) {
+ debugln!("usage::needs_flags_tag:iter:iter: Group is required");
+ continue 'outer;
+ }
+ }
+ }
+ if f.is_set(ArgSettings::Hidden) {
+ continue;
+ }
+ debugln!("usage::needs_flags_tag:iter: [FLAGS] required");
+ return true;
+ }
+
+ debugln!("usage::needs_flags_tag: [FLAGS] not required");
+ false
+}
+
+// Returns the required args in usage string form by fully unrolling all groups
+pub fn get_required_usage_from<'a, 'b>(
+ p: &Parser<'a, 'b>,
+ reqs: &[&'a str],
+ matcher: Option<&ArgMatcher<'a>>,
+ extra: Option<&str>,
+ incl_last: bool,
+) -> VecDeque<String> {
+ debugln!(
+ "usage::get_required_usage_from: reqs={:?}, extra={:?}",
+ reqs,
+ extra
+ );
+ let mut desc_reqs: Vec<&str> = vec![];
+ desc_reqs.extend(extra);
+ let mut new_reqs: Vec<&str> = vec![];
+ macro_rules! get_requires {
+ (@group $a: ident, $v:ident, $p:ident) => {{
+ if let Some(rl) = p.groups.iter()
+ .filter(|g| g.requires.is_some())
+ .find(|g| &g.name == $a)
+ .map(|g| g.requires.as_ref().unwrap()) {
+ for r in rl {
+ if !$p.contains(&r) {
+ debugln!("usage::get_required_usage_from:iter:{}: adding group req={:?}",
+ $a, r);
+ $v.push(r);
+ }
+ }
+ }
+ }};
+ ($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{
+ if let Some(rl) = p.$what.$how()
+ .filter(|a| a.b.requires.is_some())
+ .find(|arg| &arg.b.name == $a)
+ .map(|a| a.b.requires.as_ref().unwrap()) {
+ for &(_, r) in rl.iter() {
+ if !$p.contains(&r) {
+ debugln!("usage::get_required_usage_from:iter:{}: adding arg req={:?}",
+ $a, r);
+ $v.push(r);
+ }
+ }
+ }
+ }};
+ }
+ // initialize new_reqs
+ for a in reqs {
+ get_requires!(a, flags, iter, new_reqs, reqs);
+ get_requires!(a, opts, iter, new_reqs, reqs);
+ get_requires!(a, positionals, values, new_reqs, reqs);
+ get_requires!(@group a, new_reqs, reqs);
+ }
+ desc_reqs.extend_from_slice(&*new_reqs);
+ debugln!(
+ "usage::get_required_usage_from: after init desc_reqs={:?}",
+ desc_reqs
+ );
+ loop {
+ let mut tmp = vec![];
+ for a in &new_reqs {
+ get_requires!(a, flags, iter, tmp, desc_reqs);
+ get_requires!(a, opts, iter, tmp, desc_reqs);
+ get_requires!(a, positionals, values, tmp, desc_reqs);
+ get_requires!(@group a, tmp, desc_reqs);
+ }
+ if tmp.is_empty() {
+ debugln!("usage::get_required_usage_from: no more children");
+ break;
+ } else {
+ debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp);
+ debugln!(
+ "usage::get_required_usage_from: after iter new_reqs={:?}",
+ new_reqs
+ );
+ desc_reqs.extend_from_slice(&*new_reqs);
+ new_reqs.clear();
+ new_reqs.extend_from_slice(&*tmp);
+ debugln!(
+ "usage::get_required_usage_from: after iter desc_reqs={:?}",
+ desc_reqs
+ );
+ }
+ }
+ desc_reqs.extend_from_slice(reqs);
+ desc_reqs.sort();
+ desc_reqs.dedup();
+ debugln!(
+ "usage::get_required_usage_from: final desc_reqs={:?}",
+ desc_reqs
+ );
+ let mut ret_val = VecDeque::new();
+ let args_in_groups = p.groups
+ .iter()
+ .filter(|gn| desc_reqs.contains(&gn.name))
+ .flat_map(|g| p.arg_names_in_group(g.name))
+ .collect::<Vec<_>>();
+
+ let pmap = if let Some(m) = matcher {
+ desc_reqs
+ .iter()
+ .filter(|a| p.positionals.values().any(|p| &&p.b.name == a))
+ .filter(|&pos| !m.contains(pos))
+ .filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos))
+ .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
+ .filter(|pos| !args_in_groups.contains(&pos.b.name))
+ .map(|pos| (pos.index, pos))
+ .collect::<BTreeMap<u64, &PosBuilder>>() // sort by index
+ } else {
+ desc_reqs
+ .iter()
+ .filter(|a| p.positionals.values().any(|pos| &&pos.b.name == a))
+ .filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos))
+ .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
+ .filter(|pos| !args_in_groups.contains(&pos.b.name))
+ .map(|pos| (pos.index, pos))
+ .collect::<BTreeMap<u64, &PosBuilder>>() // sort by index
+ };
+ debugln!(
+ "usage::get_required_usage_from: args_in_groups={:?}",
+ args_in_groups
+ );
+ for &p in pmap.values() {
+ let s = p.to_string();
+ if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
+ ret_val.push_back(s);
+ }
+ }
+ for a in desc_reqs
+ .iter()
+ .filter(|name| !p.positionals.values().any(|p| &&p.b.name == name))
+ .filter(|name| !p.groups.iter().any(|g| &&g.name == name))
+ .filter(|name| !args_in_groups.contains(name))
+ .filter(|name| {
+ !(matcher.is_some() && matcher.as_ref().unwrap().contains(name))
+ }) {
+ debugln!("usage::get_required_usage_from:iter:{}:", a);
+ let arg = find_by_name!(p, *a, flags, iter)
+ .map(|f| f.to_string())
+ .unwrap_or_else(|| {
+ find_by_name!(p, *a, opts, iter)
+ .map(|o| o.to_string())
+ .expect(INTERNAL_ERROR_MSG)
+ });
+ ret_val.push_back(arg);
+ }
+ let mut g_vec: Vec<String> = vec![];
+ for g in desc_reqs
+ .iter()
+ .filter(|n| p.groups.iter().any(|g| &&g.name == n))
+ {
+ let g_string = p.args_in_group(g).join("|");
+ let elem = format!("<{}>", &g_string[..g_string.len()]);
+ if !g_vec.contains(&elem) {
+ g_vec.push(elem);
+ }
+ }
+ for g in g_vec {
+ ret_val.push_back(g);
+ }
+
+ ret_val
+}
diff --git a/clap/src/app/validator.rs b/clap/src/app/validator.rs
new file mode 100644
index 0000000..181b831
--- /dev/null
+++ b/clap/src/app/validator.rs
@@ -0,0 +1,573 @@
+// std
+use std::fmt::Display;
+#[allow(deprecated, unused_imports)]
+use std::ascii::AsciiExt;
+
+// Internal
+use INTERNAL_ERROR_MSG;
+use INVALID_UTF8;
+use args::{AnyArg, ArgMatcher, MatchedArg};
+use args::settings::ArgSettings;
+use errors::{Error, ErrorKind};
+use errors::Result as ClapResult;
+use app::settings::AppSettings as AS;
+use app::parser::{ParseResult, Parser};
+use fmt::{Colorizer, ColorizerOption};
+use app::usage;
+
+pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
+where
+ 'a: 'b,
+ 'b: 'z;
+
+impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
+ pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) }
+
+ pub fn validate(
+ &mut self,
+ needs_val_of: ParseResult<'a>,
+ subcmd_name: Option<String>,
+ matcher: &mut ArgMatcher<'a>,
+ ) -> ClapResult<()> {
+ debugln!("Validator::validate;");
+ let mut reqs_validated = false;
+ self.0.add_env(matcher)?;
+ self.0.add_defaults(matcher)?;
+ if let ParseResult::Opt(a) = needs_val_of {
+ debugln!("Validator::validate: needs_val_of={:?}", a);
+ let o = {
+ self.0
+ .opts
+ .iter()
+ .find(|o| o.b.name == a)
+ .expect(INTERNAL_ERROR_MSG)
+ .clone()
+ };
+ self.validate_required(matcher)?;
+ reqs_validated = true;
+ let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
+ v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
+ } else {
+ true
+ };
+ if should_err {
+ return Err(Error::empty_value(
+ &o,
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ }
+
+ if matcher.is_empty() && matcher.subcommand_name().is_none()
+ && self.0.is_set(AS::ArgRequiredElseHelp)
+ {
+ let mut out = vec![];
+ self.0.write_help_err(&mut out)?;
+ return Err(Error {
+ message: String::from_utf8_lossy(&*out).into_owned(),
+ kind: ErrorKind::MissingArgumentOrSubcommand,
+ info: None,
+ });
+ }
+ self.validate_blacklist(matcher)?;
+ if !(self.0.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) && !reqs_validated {
+ self.validate_required(matcher)?;
+ }
+ self.validate_matched_args(matcher)?;
+ matcher.usage(usage::create_usage_with_title(self.0, &[]));
+
+ Ok(())
+ }
+
+ fn validate_arg_values<A>(
+ &self,
+ arg: &A,
+ ma: &MatchedArg,
+ matcher: &ArgMatcher<'a>,
+ ) -> ClapResult<()>
+ where
+ A: AnyArg<'a, 'b> + Display,
+ {
+ debugln!("Validator::validate_arg_values: arg={:?}", arg.name());
+ for val in &ma.vals {
+ if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
+ debugln!(
+ "Validator::validate_arg_values: invalid UTF-8 found in val {:?}",
+ val
+ );
+ return Err(Error::invalid_utf8(
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ if let Some(p_vals) = arg.possible_vals() {
+ debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals);
+ let val_str = val.to_string_lossy();
+ let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
+ p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str))
+ } else {
+ p_vals.contains(&&*val_str)
+ };
+ if !ok {
+ return Err(Error::invalid_value(
+ val_str,
+ p_vals,
+ arg,
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ }
+ if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty()
+ && matcher.contains(&*arg.name())
+ {
+ debugln!("Validator::validate_arg_values: illegal empty val found");
+ return Err(Error::empty_value(
+ arg,
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ if let Some(vtor) = arg.validator() {
+ debug!("Validator::validate_arg_values: checking validator...");
+ if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
+ sdebugln!("error");
+ return Err(Error::value_validation(Some(arg), e, self.0.color()));
+ } else {
+ sdebugln!("good");
+ }
+ }
+ if let Some(vtor) = arg.validator_os() {
+ debug!("Validator::validate_arg_values: checking validator_os...");
+ if let Err(e) = vtor(val) {
+ sdebugln!("error");
+ return Err(Error::value_validation(
+ Some(arg),
+ (*e).to_string_lossy().to_string(),
+ self.0.color(),
+ ));
+ } else {
+ sdebugln!("good");
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> {
+ debugln!("build_err!: name={}", name);
+ let mut c_with = find_from!(self.0, &name, blacklist, matcher);
+ c_with = c_with.or(
+ self.0.find_any_arg(name).map_or(None, |aa| aa.blacklist())
+ .map_or(None,
+ |bl| bl.iter().find(|arg| matcher.contains(arg)))
+ .map_or(None, |an| self.0.find_any_arg(an))
+ .map_or(None, |aa| Some(format!("{}", aa)))
+ );
+ debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
+// matcher.remove(&name);
+ let usg = usage::create_error_usage(self.0, matcher, None);
+ if let Some(f) = find_by_name!(self.0, name, flags, iter) {
+ debugln!("build_err!: It was a flag...");
+ Err(Error::argument_conflict(f, c_with, &*usg, self.0.color()))
+ } else if let Some(o) = find_by_name!(self.0, name, opts, iter) {
+ debugln!("build_err!: It was an option...");
+ Err(Error::argument_conflict(o, c_with, &*usg, self.0.color()))
+ } else {
+ match find_by_name!(self.0, name, positionals, values) {
+ Some(p) => {
+ debugln!("build_err!: It was a positional...");
+ Err(Error::argument_conflict(p, c_with, &*usg, self.0.color()))
+ },
+ None => panic!(INTERNAL_ERROR_MSG)
+ }
+ }
+ }
+
+ fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
+ debugln!("Validator::validate_blacklist;");
+ let mut conflicts: Vec<&str> = vec![];
+ for (&name, _) in matcher.iter() {
+ debugln!("Validator::validate_blacklist:iter:{};", name);
+ if let Some(grps) = self.0.groups_for_arg(name) {
+ for grp in &grps {
+ if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) {
+ if !g.multiple {
+ for arg in &g.args {
+ if arg == &name {
+ continue;
+ }
+ conflicts.push(arg);
+ }
+ }
+ if let Some(ref gc) = g.conflicts {
+ conflicts.extend(&*gc);
+ }
+ }
+ }
+ }
+ if let Some(arg) = find_any_by_name!(self.0, name) {
+ if let Some(bl) = arg.blacklist() {
+ for conf in bl {
+ if matcher.get(conf).is_some() {
+ conflicts.push(conf);
+ }
+ }
+ }
+ } else {
+ debugln!("Validator::validate_blacklist:iter:{}:group;", name);
+ let args = self.0.arg_names_in_group(name);
+ for arg in &args {
+ debugln!("Validator::validate_blacklist:iter:{}:group:iter:{};", name, arg);
+ if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() {
+ for conf in bl {
+ if matcher.get(conf).is_some() {
+ conflicts.push(conf);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for name in &conflicts {
+ debugln!(
+ "Validator::validate_blacklist:iter:{}: Checking blacklisted arg",
+ name
+ );
+ let mut should_err = false;
+ if self.0.groups.iter().any(|g| &g.name == name) {
+ debugln!(
+ "Validator::validate_blacklist:iter:{}: groups contains it...",
+ name
+ );
+ for n in self.0.arg_names_in_group(name) {
+ debugln!(
+ "Validator::validate_blacklist:iter:{}:iter:{}: looking in group...",
+ name,
+ n
+ );
+ if matcher.contains(n) {
+ debugln!(
+ "Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...",
+ name,
+ n
+ );
+ return self.build_err(n, matcher);
+ }
+ }
+ } else if let Some(ma) = matcher.get(name) {
+ debugln!(
+ "Validator::validate_blacklist:iter:{}: matcher contains it...",
+ name
+ );
+ should_err = ma.occurs > 0;
+ }
+ if should_err {
+ return self.build_err(*name, matcher);
+ }
+ }
+ Ok(())
+ }
+
+ fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
+ debugln!("Validator::validate_matched_args;");
+ for (name, ma) in matcher.iter() {
+ debugln!(
+ "Validator::validate_matched_args:iter:{}: vals={:#?}",
+ name,
+ ma.vals
+ );
+ if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
+ self.validate_arg_num_vals(opt, ma, matcher)?;
+ self.validate_arg_values(opt, ma, matcher)?;
+ self.validate_arg_requires(opt, ma, matcher)?;
+ self.validate_arg_num_occurs(opt, ma, matcher)?;
+ } else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) {
+ self.validate_arg_requires(flag, ma, matcher)?;
+ self.validate_arg_num_occurs(flag, ma, matcher)?;
+ } else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) {
+ self.validate_arg_num_vals(pos, ma, matcher)?;
+ self.validate_arg_num_occurs(pos, ma, matcher)?;
+ self.validate_arg_values(pos, ma, matcher)?;
+ self.validate_arg_requires(pos, ma, matcher)?;
+ } else {
+ let grp = self.0
+ .groups
+ .iter()
+ .find(|g| &g.name == name)
+ .expect(INTERNAL_ERROR_MSG);
+ if let Some(ref g_reqs) = grp.requires {
+ if g_reqs.iter().any(|&n| !matcher.contains(n)) {
+ return self.missing_required_error(matcher, None);
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn validate_arg_num_occurs<A>(
+ &self,
+ a: &A,
+ ma: &MatchedArg,
+ matcher: &ArgMatcher,
+ ) -> ClapResult<()>
+ where
+ A: AnyArg<'a, 'b> + Display,
+ {
+ debugln!("Validator::validate_arg_num_occurs: a={};", a.name());
+ if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
+ // Not the first time, and we don't allow multiples
+ return Err(Error::unexpected_multiple_usage(
+ a,
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ Ok(())
+ }
+
+ fn validate_arg_num_vals<A>(
+ &self,
+ a: &A,
+ ma: &MatchedArg,
+ matcher: &ArgMatcher,
+ ) -> ClapResult<()>
+ where
+ A: AnyArg<'a, 'b> + Display,
+ {
+ debugln!("Validator::validate_arg_num_vals:{}", a.name());
+ if let Some(num) = a.num_vals() {
+ debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num);
+ let should_err = if a.is_set(ArgSettings::Multiple) {
+ ((ma.vals.len() as u64) % num) != 0
+ } else {
+ num != (ma.vals.len() as u64)
+ };
+ if should_err {
+ debugln!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
+ return Err(Error::wrong_number_of_values(
+ a,
+ num,
+ if a.is_set(ArgSettings::Multiple) {
+ (ma.vals.len() % num as usize)
+ } else {
+ ma.vals.len()
+ },
+ if ma.vals.len() == 1
+ || (a.is_set(ArgSettings::Multiple) && (ma.vals.len() % num as usize) == 1)
+ {
+ "as"
+ } else {
+ "ere"
+ },
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ }
+ if let Some(num) = a.max_vals() {
+ debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num);
+ if (ma.vals.len() as u64) > num {
+ debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues");
+ return Err(Error::too_many_values(
+ ma.vals
+ .iter()
+ .last()
+ .expect(INTERNAL_ERROR_MSG)
+ .to_str()
+ .expect(INVALID_UTF8),
+ a,
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ }
+ let min_vals_zero = if let Some(num) = a.min_vals() {
+ debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num);
+ if (ma.vals.len() as u64) < num && num != 0 {
+ debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues");
+ return Err(Error::too_few_values(
+ a,
+ num,
+ ma.vals.len(),
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ num == 0
+ } else {
+ false
+ };
+ // Issue 665 (https://github.com/clap-rs/clap/issues/665)
+ // Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
+ if a.takes_value() && !min_vals_zero && ma.vals.is_empty() {
+ return Err(Error::empty_value(
+ a,
+ &*usage::create_error_usage(self.0, matcher, None),
+ self.0.color(),
+ ));
+ }
+ Ok(())
+ }
+
+ fn validate_arg_requires<A>(
+ &self,
+ a: &A,
+ ma: &MatchedArg,
+ matcher: &ArgMatcher,
+ ) -> ClapResult<()>
+ where
+ A: AnyArg<'a, 'b> + Display,
+ {
+ debugln!("Validator::validate_arg_requires:{};", a.name());
+ if let Some(a_reqs) = a.requires() {
+ for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
+ let missing_req =
+ |v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name);
+ if ma.vals.iter().any(missing_req) {
+ return self.missing_required_error(matcher, None);
+ }
+ }
+ for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) {
+ if !matcher.contains(name) {
+ return self.missing_required_error(matcher, Some(name));
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> {
+ debugln!(
+ "Validator::validate_required: required={:?};",
+ self.0.required
+ );
+
+ let mut should_err = false;
+ let mut to_rem = Vec::new();
+ for name in &self.0.required {
+ debugln!("Validator::validate_required:iter:{}:", name);
+ if matcher.contains(name) {
+ continue;
+ }
+ if to_rem.contains(name) {
+ continue;
+ } else if let Some(a) = find_any_by_name!(self.0, *name) {
+ if self.is_missing_required_ok(a, matcher) {
+ to_rem.push(a.name());
+ if let Some(reqs) = a.requires() {
+ for r in reqs
+ .iter()
+ .filter(|&&(val, _)| val.is_none())
+ .map(|&(_, name)| name)
+ {
+ to_rem.push(r);
+ }
+ }
+ continue;
+ }
+ }
+ should_err = true;
+ break;
+ }
+ if should_err {
+ for r in &to_rem {
+ 'inner: for i in (0 .. self.0.required.len()).rev() {
+ if &self.0.required[i] == r {
+ self.0.required.swap_remove(i);
+ break 'inner;
+ }
+ }
+ }
+ return self.missing_required_error(matcher, None);
+ }
+
+ // Validate the conditionally required args
+ for &(a, v, r) in &self.0.r_ifs {
+ if let Some(ma) = matcher.get(a) {
+ if matcher.get(r).is_none() && ma.vals.iter().any(|val| val == v) {
+ return self.missing_required_error(matcher, Some(r));
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
+ debugln!("Validator::validate_arg_conflicts: a={:?};", a.name());
+ a.blacklist().map(|bl| {
+ bl.iter().any(|conf| {
+ matcher.contains(conf)
+ || self.0
+ .groups
+ .iter()
+ .find(|g| &g.name == conf)
+ .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
+ })
+ })
+ }
+
+ fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
+ debugln!("Validator::validate_required_unless: a={:?};", a.name());
+ macro_rules! check {
+ ($how:ident, $_self:expr, $a:ident, $m:ident) => {{
+ $a.required_unless().map(|ru| {
+ ru.iter().$how(|n| {
+ $m.contains(n) || {
+ if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) {
+ grp.args.iter().any(|arg| $m.contains(arg))
+ } else {
+ false
+ }
+ }
+ })
+ })
+ }};
+ }
+ if a.is_set(ArgSettings::RequiredUnlessAll) {
+ check!(all, self.0, a, matcher)
+ } else {
+ check!(any, self.0, a, matcher)
+ }
+ }
+
+ fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> {
+ debugln!("Validator::missing_required_error: extra={:?}", extra);
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: self.0.color(),
+ });
+ let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>();
+ if let Some(r) = extra {
+ reqs.push(r);
+ }
+ reqs.retain(|n| !matcher.contains(n));
+ reqs.dedup();
+ debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
+ let req_args =
+ usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true)
+ .iter()
+ .fold(String::new(), |acc, s| {
+ acc + &format!("\n {}", c.error(s))[..]
+ });
+ debugln!(
+ "Validator::missing_required_error: req_args={:#?}",
+ req_args
+ );
+ Err(Error::missing_required_argument(
+ &*req_args,
+ &*usage::create_error_usage(self.0, matcher, extra),
+ self.0.color(),
+ ))
+ }
+
+ #[inline]
+ fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool {
+ debugln!("Validator::is_missing_required_ok: a={}", a.name());
+ self.validate_arg_conflicts(a, matcher).unwrap_or(false)
+ || self.validate_required_unless(a, matcher).unwrap_or(false)
+ }
+}
diff --git a/clap/src/args/any_arg.rs b/clap/src/args/any_arg.rs
new file mode 100644
index 0000000..eee5228
--- /dev/null
+++ b/clap/src/args/any_arg.rs
@@ -0,0 +1,74 @@
+// Std
+use std::rc::Rc;
+use std::fmt as std_fmt;
+use std::ffi::{OsStr, OsString};
+
+// Internal
+use args::settings::ArgSettings;
+use map::{self, VecMap};
+use INTERNAL_ERROR_MSG;
+
+#[doc(hidden)]
+pub trait AnyArg<'n, 'e>: std_fmt::Display {
+ fn name(&self) -> &'n str;
+ fn overrides(&self) -> Option<&[&'e str]>;
+ fn aliases(&self) -> Option<Vec<&'e str>>;
+ fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]>;
+ fn blacklist(&self) -> Option<&[&'e str]>;
+ fn required_unless(&self) -> Option<&[&'e str]>;
+ fn is_set(&self, ArgSettings) -> bool;
+ fn set(&mut self, ArgSettings);
+ fn has_switch(&self) -> bool;
+ fn max_vals(&self) -> Option<u64>;
+ fn min_vals(&self) -> Option<u64>;
+ fn num_vals(&self) -> Option<u64>;
+ fn possible_vals(&self) -> Option<&[&'e str]>;
+ fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>>;
+ fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> Result<(), OsString>>>;
+ fn short(&self) -> Option<char>;
+ fn long(&self) -> Option<&'e str>;
+ fn val_delim(&self) -> Option<char>;
+ fn takes_value(&self) -> bool;
+ fn val_names(&self) -> Option<&VecMap<&'e str>>;
+ fn help(&self) -> Option<&'e str>;
+ fn long_help(&self) -> Option<&'e str>;
+ fn default_val(&self) -> Option<&'e OsStr>;
+ fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>>;
+ fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)>;
+ fn longest_filter(&self) -> bool;
+ fn val_terminator(&self) -> Option<&'e str>;
+}
+
+pub trait DispOrder {
+ fn disp_ord(&self) -> usize;
+}
+
+impl<'n, 'e, 'z, T: ?Sized> AnyArg<'n, 'e> for &'z T where T: AnyArg<'n, 'e> + 'z {
+ fn name(&self) -> &'n str { (*self).name() }
+ fn overrides(&self) -> Option<&[&'e str]> { (*self).overrides() }
+ fn aliases(&self) -> Option<Vec<&'e str>> { (*self).aliases() }
+ fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { (*self).requires() }
+ fn blacklist(&self) -> Option<&[&'e str]> { (*self).blacklist() }
+ fn required_unless(&self) -> Option<&[&'e str]> { (*self).required_unless() }
+ fn is_set(&self, a: ArgSettings) -> bool { (*self).is_set(a) }
+ fn set(&mut self, _: ArgSettings) { panic!(INTERNAL_ERROR_MSG) }
+ fn has_switch(&self) -> bool { (*self).has_switch() }
+ fn max_vals(&self) -> Option<u64> { (*self).max_vals() }
+ fn min_vals(&self) -> Option<u64> { (*self).min_vals() }
+ fn num_vals(&self) -> Option<u64> { (*self).num_vals() }
+ fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() }
+ fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>> { (*self).validator() }
+ fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> Result<(), OsString>>> { (*self).validator_os() }
+ fn short(&self) -> Option<char> { (*self).short() }
+ fn long(&self) -> Option<&'e str> { (*self).long() }
+ fn val_delim(&self) -> Option<char> { (*self).val_delim() }
+ fn takes_value(&self) -> bool { (*self).takes_value() }
+ fn val_names(&self) -> Option<&VecMap<&'e str>> { (*self).val_names() }
+ fn help(&self) -> Option<&'e str> { (*self).help() }
+ fn long_help(&self) -> Option<&'e str> { (*self).long_help() }
+ fn default_val(&self) -> Option<&'e OsStr> { (*self).default_val() }
+ fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> { (*self).default_vals_ifs() }
+ fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { (*self).env() }
+ fn longest_filter(&self) -> bool { (*self).longest_filter() }
+ fn val_terminator(&self) -> Option<&'e str> { (*self).val_terminator() }
+}
diff --git a/clap/src/args/arg.rs b/clap/src/args/arg.rs
new file mode 100644
index 0000000..50a30ab
--- /dev/null
+++ b/clap/src/args/arg.rs
@@ -0,0 +1,3954 @@
+#[cfg(feature = "yaml")]
+use std::collections::BTreeMap;
+use std::rc::Rc;
+use std::ffi::{OsStr, OsString};
+#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
+use osstringext::OsStrExt3;
+#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
+use std::os::unix::ffi::OsStrExt;
+use std::env;
+
+#[cfg(feature = "yaml")]
+use yaml_rust::Yaml;
+use map::VecMap;
+
+use usage_parser::UsageParser;
+use args::settings::ArgSettings;
+use args::arg_builder::{Base, Switched, Valued};
+
+/// The abstract representation of a command line argument. Used to set all the options and
+/// relationships that define a valid argument for the program.
+///
+/// There are two methods for constructing [`Arg`]s, using the builder pattern and setting options
+/// manually, or using a usage string which is far less verbose but has fewer options. You can also
+/// use a combination of the two methods to achieve the best of both worlds.
+///
+/// # Examples
+///
+/// ```rust
+/// # use clap::Arg;
+/// // Using the traditional builder pattern and setting each option manually
+/// let cfg = Arg::with_name("config")
+/// .short("c")
+/// .long("config")
+/// .takes_value(true)
+/// .value_name("FILE")
+/// .help("Provides a config file to myprog");
+/// // Using a usage string (setting a similar argument to the one above)
+/// let input = Arg::from_usage("-i, --input=[FILE] 'Provides an input file to the program'");
+/// ```
+/// [`Arg`]: ./struct.Arg.html
+#[allow(missing_debug_implementations)]
+#[derive(Default, Clone)]
+pub struct Arg<'a, 'b>
+where
+ 'a: 'b,
+{
+ #[doc(hidden)] pub b: Base<'a, 'b>,
+ #[doc(hidden)] pub s: Switched<'b>,
+ #[doc(hidden)] pub v: Valued<'a, 'b>,
+ #[doc(hidden)] pub index: Option<u64>,
+ #[doc(hidden)] pub r_ifs: Option<Vec<(&'a str, &'b str)>>,
+}
+
+impl<'a, 'b> Arg<'a, 'b> {
+ /// Creates a new instance of [`Arg`] using a unique string name. The name will be used to get
+ /// information about whether or not the argument was used at runtime, get values, set
+ /// relationships with other args, etc..
+ ///
+ /// **NOTE:** In the case of arguments that take values (i.e. [`Arg::takes_value(true)`])
+ /// and positional arguments (i.e. those without a preceding `-` or `--`) the name will also
+ /// be displayed when the user prints the usage/help information of the program.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("config")
+ /// # ;
+ /// ```
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ /// [`Arg`]: ./struct.Arg.html
+ pub fn with_name(n: &'a str) -> Self {
+ Arg {
+ b: Base::new(n),
+ ..Default::default()
+ }
+ }
+
+ /// Creates a new instance of [`Arg`] from a .yml (YAML) file.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore
+ /// # #[macro_use]
+ /// # extern crate clap;
+ /// # use clap::Arg;
+ /// # fn main() {
+ /// let yml = load_yaml!("arg.yml");
+ /// let arg = Arg::from_yaml(yml);
+ /// # }
+ /// ```
+ /// [`Arg`]: ./struct.Arg.html
+ #[cfg(feature = "yaml")]
+ pub fn from_yaml(y: &BTreeMap<Yaml, Yaml>) -> Arg {
+ // We WANT this to panic on error...so expect() is good.
+ let name_yml = y.keys().nth(0).unwrap();
+ let name_str = name_yml.as_str().unwrap();
+ let mut a = Arg::with_name(name_str);
+ let arg_settings = y.get(name_yml).unwrap().as_hash().unwrap();
+
+ for (k, v) in arg_settings.iter() {
+ a = match k.as_str().unwrap() {
+ "short" => yaml_to_str!(a, v, short),
+ "long" => yaml_to_str!(a, v, long),
+ "aliases" => yaml_vec_or_str!(v, a, alias),
+ "help" => yaml_to_str!(a, v, help),
+ "long_help" => yaml_to_str!(a, v, long_help),
+ "required" => yaml_to_bool!(a, v, required),
+ "required_if" => yaml_tuple2!(a, v, required_if),
+ "required_ifs" => yaml_tuple2!(a, v, required_if),
+ "takes_value" => yaml_to_bool!(a, v, takes_value),
+ "index" => yaml_to_u64!(a, v, index),
+ "global" => yaml_to_bool!(a, v, global),
+ "multiple" => yaml_to_bool!(a, v, multiple),
+ "hidden" => yaml_to_bool!(a, v, hidden),
+ "next_line_help" => yaml_to_bool!(a, v, next_line_help),
+ "empty_values" => yaml_to_bool!(a, v, empty_values),
+ "group" => yaml_to_str!(a, v, group),
+ "number_of_values" => yaml_to_u64!(a, v, number_of_values),
+ "max_values" => yaml_to_u64!(a, v, max_values),
+ "min_values" => yaml_to_u64!(a, v, min_values),
+ "value_name" => yaml_to_str!(a, v, value_name),
+ "use_delimiter" => yaml_to_bool!(a, v, use_delimiter),
+ "allow_hyphen_values" => yaml_to_bool!(a, v, allow_hyphen_values),
+ "last" => yaml_to_bool!(a, v, last),
+ "require_delimiter" => yaml_to_bool!(a, v, require_delimiter),
+ "value_delimiter" => yaml_to_str!(a, v, value_delimiter),
+ "required_unless" => yaml_to_str!(a, v, required_unless),
+ "display_order" => yaml_to_usize!(a, v, display_order),
+ "default_value" => yaml_to_str!(a, v, default_value),
+ "default_value_if" => yaml_tuple3!(a, v, default_value_if),
+ "default_value_ifs" => yaml_tuple3!(a, v, default_value_if),
+ "env" => yaml_to_str!(a, v, env),
+ "value_names" => yaml_vec_or_str!(v, a, value_name),
+ "groups" => yaml_vec_or_str!(v, a, group),
+ "requires" => yaml_vec_or_str!(v, a, requires),
+ "requires_if" => yaml_tuple2!(a, v, requires_if),
+ "requires_ifs" => yaml_tuple2!(a, v, requires_if),
+ "conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with),
+ "overrides_with" => yaml_vec_or_str!(v, a, overrides_with),
+ "possible_values" => yaml_vec_or_str!(v, a, possible_value),
+ "case_insensitive" => yaml_to_bool!(a, v, case_insensitive),
+ "required_unless_one" => yaml_vec_or_str!(v, a, required_unless),
+ "required_unless_all" => {
+ a = yaml_vec_or_str!(v, a, required_unless);
+ a.setb(ArgSettings::RequiredUnlessAll);
+ a
+ }
+ s => panic!(
+ "Unknown Arg setting '{}' in YAML file for arg '{}'",
+ s, name_str
+ ),
+ }
+ }
+
+ a
+ }
+
+ /// Creates a new instance of [`Arg`] from a usage string. Allows creation of basic settings
+ /// for the [`Arg`]. The syntax is flexible, but there are some rules to follow.
+ ///
+ /// **NOTE**: Not all settings may be set using the usage string method. Some properties are
+ /// only available via the builder pattern.
+ ///
+ /// **NOTE**: Only ASCII values are officially supported in [`Arg::from_usage`] strings. Some
+ /// UTF-8 codepoints may work just fine, but this is not guaranteed.
+ ///
+ /// # Syntax
+ ///
+ /// Usage strings typically following the form:
+ ///
+ /// ```notrust
+ /// [explicit name] [short] [long] [value names] [help string]
+ /// ```
+ ///
+ /// This is not a hard rule as the attributes can appear in other orders. There are also
+ /// several additional sigils which denote additional settings. Below are the details of each
+ /// portion of the string.
+ ///
+ /// ### Explicit Name
+ ///
+ /// This is an optional field, if it's omitted the argument will use one of the additional
+ /// fields as the name using the following priority order:
+ ///
+ /// * Explicit Name (This always takes precedence when present)
+ /// * Long
+ /// * Short
+ /// * Value Name
+ ///
+ /// `clap` determines explicit names as the first string of characters between either `[]` or
+ /// `<>` where `[]` has the dual notation of meaning the argument is optional, and `<>` meaning
+ /// the argument is required.
+ ///
+ /// Explicit names may be followed by:
+ /// * The multiple denotation `...`
+ ///
+ /// Example explicit names as follows (`ename` for an optional argument, and `rname` for a
+ /// required argument):
+ ///
+ /// ```notrust
+ /// [ename] -s, --long 'some flag'
+ /// <rname> -r, --longer 'some other flag'
+ /// ```
+ ///
+ /// ### Short
+ ///
+ /// This is set by placing a single character after a leading `-`.
+ ///
+ /// Shorts may be followed by
+ /// * The multiple denotation `...`
+ /// * An optional comma `,` which is cosmetic only
+ /// * Value notation
+ ///
+ /// Example shorts are as follows (`-s`, and `-r`):
+ ///
+ /// ```notrust
+ /// -s, --long 'some flag'
+ /// <rname> -r [val], --longer 'some option'
+ /// ```
+ ///
+ /// ### Long
+ ///
+ /// This is set by placing a word (no spaces) after a leading `--`.
+ ///
+ /// Shorts may be followed by
+ /// * The multiple denotation `...`
+ /// * Value notation
+ ///
+ /// Example longs are as follows (`--some`, and `--rapid`):
+ ///
+ /// ```notrust
+ /// -s, --some 'some flag'
+ /// --rapid=[FILE] 'some option'
+ /// ```
+ ///
+ /// ### Values (Value Notation)
+ ///
+ /// This is set by placing a word(s) between `[]` or `<>` optionally after `=` (although this
+ /// is cosmetic only and does not affect functionality). If an explicit name has **not** been
+ /// set, using `<>` will denote a required argument, and `[]` will denote an optional argument
+ ///
+ /// Values may be followed by
+ /// * The multiple denotation `...`
+ /// * More Value notation
+ ///
+ /// More than one value will also implicitly set the arguments number of values, i.e. having
+ /// two values, `--option [val1] [val2]` specifies that in order for option to be satisified it
+ /// must receive exactly two values
+ ///
+ /// Example values are as follows (`FILE`, and `SPEED`):
+ ///
+ /// ```notrust
+ /// -s, --some [FILE] 'some option'
+ /// --rapid=<SPEED>... 'some required multiple option'
+ /// ```
+ ///
+ /// ### Help String
+ ///
+ /// The help string is denoted between a pair of single quotes `''` and may contain any
+ /// characters.
+ ///
+ /// Example help strings are as follows:
+ ///
+ /// ```notrust
+ /// -s, --some [FILE] 'some option'
+ /// --rapid=<SPEED>... 'some required multiple option'
+ /// ```
+ ///
+ /// ### Additional Sigils
+ ///
+ /// Multiple notation `...` (three consecutive dots/periods) specifies that this argument may
+ /// be used multiple times. Do not confuse multiple occurrences (`...`) with multiple values.
+ /// `--option val1 val2` is a single occurrence with multiple values. `--flag --flag` is
+ /// multiple occurrences (and then you can obviously have instances of both as well)
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// App::new("prog")
+ /// .args(&[
+ /// Arg::from_usage("--config <FILE> 'a required file for the configuration and no short'"),
+ /// Arg::from_usage("-d, --debug... 'turns on debugging information and allows multiples'"),
+ /// Arg::from_usage("[input] 'an optional input file to use'")
+ /// ])
+ /// # ;
+ /// ```
+ /// [`Arg`]: ./struct.Arg.html
+ /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage
+ pub fn from_usage(u: &'a str) -> Self {
+ let parser = UsageParser::from_usage(u);
+ parser.parse()
+ }
+
+ /// Sets the short version of the argument without the preceding `-`.
+ ///
+ /// By default `clap` automatically assigns `V` and `h` to the auto-generated `version` and
+ /// `help` arguments respectively. You may use the uppercase `V` or lowercase `h` for your own
+ /// arguments, in which case `clap` simply will not assign those to the auto-generated
+ /// `version` or `help` arguments.
+ ///
+ /// **NOTE:** Any leading `-` characters will be stripped, and only the first
+ /// non `-` character will be used as the [`short`] version
+ ///
+ /// # Examples
+ ///
+ /// To set [`short`] use a single valid UTF-8 code point. If you supply a leading `-` such as
+ /// `-c`, the `-` will be stripped.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("config")
+ /// .short("c")
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`short`] allows using the argument via a single hyphen (`-`) such as `-c`
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("config")
+ /// .short("c"))
+ /// .get_matches_from(vec![
+ /// "prog", "-c"
+ /// ]);
+ ///
+ /// assert!(m.is_present("config"));
+ /// ```
+ /// [`short`]: ./struct.Arg.html#method.short
+ pub fn short<S: AsRef<str>>(mut self, s: S) -> Self {
+ self.s.short = s.as_ref().trim_left_matches(|c| c == '-').chars().nth(0);
+ self
+ }
+
+ /// Sets the long version of the argument without the preceding `--`.
+ ///
+ /// By default `clap` automatically assigns `version` and `help` to the auto-generated
+ /// `version` and `help` arguments respectively. You may use the word `version` or `help` for
+ /// the long form of your own arguments, in which case `clap` simply will not assign those to
+ /// the auto-generated `version` or `help` arguments.
+ ///
+ /// **NOTE:** Any leading `-` characters will be stripped
+ ///
+ /// # Examples
+ ///
+ /// To set `long` use a word containing valid UTF-8 codepoints. If you supply a double leading
+ /// `--` such as `--config` they will be stripped. Hyphens in the middle of the word, however,
+ /// will *not* be stripped (i.e. `config-file` is allowed)
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("cfg")
+ /// .long("config")
+ /// # ;
+ /// ```
+ ///
+ /// Setting `long` allows using the argument via a double hyphen (`--`) such as `--config`
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config"))
+ /// .get_matches_from(vec![
+ /// "prog", "--config"
+ /// ]);
+ ///
+ /// assert!(m.is_present("cfg"));
+ /// ```
+ pub fn long(mut self, l: &'b str) -> Self {
+ self.s.long = Some(l.trim_left_matches(|c| c == '-'));
+ self
+ }
+
+ /// Allows adding a [`Arg`] alias, which function as "hidden" arguments that
+ /// automatically dispatch as if this argument was used. This is more efficient, and easier
+ /// than creating multiple hidden arguments as one only needs to check for the existence of
+ /// this command, and not all variants.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("test")
+ /// .long("test")
+ /// .alias("alias")
+ /// .takes_value(true))
+ /// .get_matches_from(vec![
+ /// "prog", "--alias", "cool"
+ /// ]);
+ /// assert!(m.is_present("test"));
+ /// assert_eq!(m.value_of("test"), Some("cool"));
+ /// ```
+ /// [`Arg`]: ./struct.Arg.html
+ pub fn alias<S: Into<&'b str>>(mut self, name: S) -> Self {
+ if let Some(ref mut als) = self.s.aliases {
+ als.push((name.into(), false));
+ } else {
+ self.s.aliases = Some(vec![(name.into(), false)]);
+ }
+ self
+ }
+
+ /// Allows adding [`Arg`] aliases, which function as "hidden" arguments that
+ /// automatically dispatch as if this argument was used. This is more efficient, and easier
+ /// than creating multiple hidden subcommands as one only needs to check for the existence of
+ /// this command, and not all variants.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("test")
+ /// .long("test")
+ /// .aliases(&["do-stuff", "do-tests", "tests"])
+ /// .help("the file to add")
+ /// .required(false))
+ /// .get_matches_from(vec![
+ /// "prog", "--do-tests"
+ /// ]);
+ /// assert!(m.is_present("test"));
+ /// ```
+ /// [`Arg`]: ./struct.Arg.html
+ pub fn aliases(mut self, names: &[&'b str]) -> Self {
+ if let Some(ref mut als) = self.s.aliases {
+ for n in names {
+ als.push((n, false));
+ }
+ } else {
+ self.s.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
+ }
+ self
+ }
+
+ /// Allows adding a [`Arg`] alias that functions exactly like those defined with
+ /// [`Arg::alias`], except that they are visible inside the help message.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("test")
+ /// .visible_alias("something-awesome")
+ /// .long("test")
+ /// .takes_value(true))
+ /// .get_matches_from(vec![
+ /// "prog", "--something-awesome", "coffee"
+ /// ]);
+ /// assert!(m.is_present("test"));
+ /// assert_eq!(m.value_of("test"), Some("coffee"));
+ /// ```
+ /// [`Arg`]: ./struct.Arg.html
+ /// [`App::alias`]: ./struct.Arg.html#method.alias
+ pub fn visible_alias<S: Into<&'b str>>(mut self, name: S) -> Self {
+ if let Some(ref mut als) = self.s.aliases {
+ als.push((name.into(), true));
+ } else {
+ self.s.aliases = Some(vec![(name.into(), true)]);
+ }
+ self
+ }
+
+ /// Allows adding multiple [`Arg`] aliases that functions exactly like those defined
+ /// with [`Arg::aliases`], except that they are visible inside the help message.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("test")
+ /// .long("test")
+ /// .visible_aliases(&["something", "awesome", "cool"]))
+ /// .get_matches_from(vec![
+ /// "prog", "--awesome"
+ /// ]);
+ /// assert!(m.is_present("test"));
+ /// ```
+ /// [`Arg`]: ./struct.Arg.html
+ /// [`App::aliases`]: ./struct.Arg.html#method.aliases
+ pub fn visible_aliases(mut self, names: &[&'b str]) -> Self {
+ if let Some(ref mut als) = self.s.aliases {
+ for n in names {
+ als.push((n, true));
+ }
+ } else {
+ self.s.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>());
+ }
+ self
+ }
+
+ /// Sets the short help text of the argument that will be displayed to the user when they print
+ /// the help information with `-h`. Typically, this is a short (one line) description of the
+ /// arg.
+ ///
+ /// **NOTE:** If only `Arg::help` is provided, and not [`Arg::long_help`] but the user requests
+ /// `--help` clap will still display the contents of `help` appropriately
+ ///
+ /// **NOTE:** Only `Arg::help` is used in completion script generation in order to be concise
+ ///
+ /// # Examples
+ ///
+ /// Any valid UTF-8 is allowed in the help text. The one exception is when one wishes to
+ /// include a newline in the help text and have the following text be properly aligned with all
+ /// the other help text.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("config")
+ /// .help("The config file used by the myprog")
+ /// # ;
+ /// ```
+ ///
+ /// Setting `help` displays a short message to the side of the argument when the user passes
+ /// `-h` or `--help` (by default).
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config")
+ /// .help("Some help text describing the --config arg"))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ ///
+ /// The above example displays
+ ///
+ /// ```notrust
+ /// helptest
+ ///
+ /// USAGE:
+ /// helptest [FLAGS]
+ ///
+ /// FLAGS:
+ /// --config Some help text describing the --config arg
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ /// ```
+ /// [`Arg::long_help`]: ./struct.Arg.html#method.long_help
+ pub fn help(mut self, h: &'b str) -> Self {
+ self.b.help = Some(h);
+ self
+ }
+
+ /// Sets the long help text of the argument that will be displayed to the user when they print
+ /// the help information with `--help`. Typically this a more detailed (multi-line) message
+ /// that describes the arg.
+ ///
+ /// **NOTE:** If only `long_help` is provided, and not [`Arg::help`] but the user requests `-h`
+ /// clap will still display the contents of `long_help` appropriately
+ ///
+ /// **NOTE:** Only [`Arg::help`] is used in completion script generation in order to be concise
+ ///
+ /// # Examples
+ ///
+ /// Any valid UTF-8 is allowed in the help text. The one exception is when one wishes to
+ /// include a newline in the help text and have the following text be properly aligned with all
+ /// the other help text.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("config")
+ /// .long_help(
+ /// "The config file used by the myprog must be in JSON format
+ /// with only valid keys and may not contain other nonsense
+ /// that cannot be read by this program. Obviously I'm going on
+ /// and on, so I'll stop now.")
+ /// # ;
+ /// ```
+ ///
+ /// Setting `help` displays a short message to the side of the argument when the user passes
+ /// `-h` or `--help` (by default).
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config")
+ /// .long_help(
+ /// "The config file used by the myprog must be in JSON format
+ /// with only valid keys and may not contain other nonsense
+ /// that cannot be read by this program. Obviously I'm going on
+ /// and on, so I'll stop now."))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ ///
+ /// The above example displays
+ ///
+ /// ```notrust
+ /// helptest
+ ///
+ /// USAGE:
+ /// helptest [FLAGS]
+ ///
+ /// FLAGS:
+ /// --config
+ /// The config file used by the myprog must be in JSON format
+ /// with only valid keys and may not contain other nonsense
+ /// that cannot be read by this program. Obviously I'm going on
+ /// and on, so I'll stop now.
+ ///
+ /// -h, --help
+ /// Prints help information
+ ///
+ /// -V, --version
+ /// Prints version information
+ /// ```
+ /// [`Arg::help`]: ./struct.Arg.html#method.help
+ pub fn long_help(mut self, h: &'b str) -> Self {
+ self.b.long_help = Some(h);
+ self
+ }
+
+ /// Specifies that this arg is the last, or final, positional argument (i.e. has the highest
+ /// index) and is *only* able to be accessed via the `--` syntax (i.e. `$ prog args --
+ /// last_arg`). Even, if no other arguments are left to parse, if the user omits the `--` syntax
+ /// they will receive an [`UnknownArgument`] error. Setting an argument to `.last(true)` also
+ /// allows one to access this arg early using the `--` syntax. Accessing an arg early, even with
+ /// the `--` syntax is otherwise not possible.
+ ///
+ /// **NOTE:** This will change the usage string to look like `$ prog [FLAGS] [-- <ARG>]` if
+ /// `ARG` is marked as `.last(true)`.
+ ///
+ /// **NOTE:** This setting will imply [`AppSettings::DontCollapseArgsInUsage`] because failing
+ /// to set this can make the usage string very confusing.
+ ///
+ /// **NOTE**: This setting only applies to positional arguments, and has no affect on FLAGS /
+ /// OPTIONS
+ ///
+ /// **CAUTION:** Setting an argument to `.last(true)` *and* having child subcommands is not
+ /// recommended with the exception of *also* using [`AppSettings::ArgsNegateSubcommands`]
+ /// (or [`AppSettings::SubcommandsNegateReqs`] if the argument marked `.last(true)` is also
+ /// marked [`.required(true)`])
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("args")
+ /// .last(true)
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::last(true)`] ensures the arg has the highest [index] of all positional args
+ /// and requires that the `--` syntax be used to access it early.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("first"))
+ /// .arg(Arg::with_name("second"))
+ /// .arg(Arg::with_name("third").last(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "one", "--", "three"
+ /// ]);
+ ///
+ /// assert!(res.is_ok());
+ /// let m = res.unwrap();
+ /// assert_eq!(m.value_of("third"), Some("three"));
+ /// assert!(m.value_of("second").is_none());
+ /// ```
+ ///
+ /// Even if the positional argument marked `.last(true)` is the only argument left to parse,
+ /// failing to use the `--` syntax results in an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("first"))
+ /// .arg(Arg::with_name("second"))
+ /// .arg(Arg::with_name("third").last(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "one", "two", "three"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+ /// ```
+ /// [`Arg::last(true)`]: ./struct.Arg.html#method.last
+ /// [index]: ./struct.Arg.html#method.index
+ /// [`AppSettings::DontCollapseArgsInUsage`]: ./enum.AppSettings.html#variant.DontCollapseArgsInUsage
+ /// [`AppSettings::ArgsNegateSubcommands`]: ./enum.AppSettings.html#variant.ArgsNegateSubcommands
+ /// [`AppSettings::SubcommandsNegateReqs`]: ./enum.AppSettings.html#variant.SubcommandsNegateReqs
+ /// [`.required(true)`]: ./struct.Arg.html#method.required
+ /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument
+ pub fn last(self, l: bool) -> Self {
+ if l {
+ self.set(ArgSettings::Last)
+ } else {
+ self.unset(ArgSettings::Last)
+ }
+ }
+
+ /// Sets whether or not the argument is required by default. Required by default means it is
+ /// required, when no other conflicting rules have been evaluated. Conflicting rules take
+ /// precedence over being required. **Default:** `false`
+ ///
+ /// **NOTE:** Flags (i.e. not positional, or arguments that take values) cannot be required by
+ /// default. This is simply because if a flag should be required, it should simply be implied
+ /// as no additional information is required from user. Flags by their very nature are simply
+ /// yes/no, or true/false.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .required(true)
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::required(true)`] requires that the argument be used at runtime.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required(true)
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config", "file.conf"
+ /// ]);
+ ///
+ /// assert!(res.is_ok());
+ /// ```
+ ///
+ /// Setting [`Arg::required(true)`] and *not* supplying that argument is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required(true)
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .get_matches_from_safe(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`Arg::required(true)`]: ./struct.Arg.html#method.required
+ pub fn required(self, r: bool) -> Self {
+ if r {
+ self.set(ArgSettings::Required)
+ } else {
+ self.unset(ArgSettings::Required)
+ }
+ }
+
+ /// Requires that options use the `--option=val` syntax (i.e. an equals between the option and
+ /// associated value) **Default:** `false`
+ ///
+ /// **NOTE:** This setting also removes the default of allowing empty values and implies
+ /// [`Arg::empty_values(false)`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .long("config")
+ /// .takes_value(true)
+ /// .require_equals(true)
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::require_equals(true)`] requires that the option have an equals sign between
+ /// it and the associated value.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .require_equals(true)
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config=file.conf"
+ /// ]);
+ ///
+ /// assert!(res.is_ok());
+ /// ```
+ ///
+ /// Setting [`Arg::require_equals(true)`] and *not* supplying the equals will cause an error
+ /// unless [`Arg::empty_values(true)`] is set.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .require_equals(true)
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config", "file.conf"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
+ /// ```
+ /// [`Arg::require_equals(true)`]: ./struct.Arg.html#method.require_equals
+ /// [`Arg::empty_values(true)`]: ./struct.Arg.html#method.empty_values
+ /// [`Arg::empty_values(false)`]: ./struct.Arg.html#method.empty_values
+ pub fn require_equals(mut self, r: bool) -> Self {
+ if r {
+ self.unsetb(ArgSettings::EmptyValues);
+ self.set(ArgSettings::RequireEquals)
+ } else {
+ self.unset(ArgSettings::RequireEquals)
+ }
+ }
+
+ /// Allows values which start with a leading hyphen (`-`)
+ ///
+ /// **WARNING**: Take caution when using this setting combined with [`Arg::multiple(true)`], as
+ /// this becomes ambiguous `$ prog --arg -- -- val`. All three `--, --, val` will be values
+ /// when the user may have thought the second `--` would constitute the normal, "Only
+ /// positional args follow" idiom. To fix this, consider using [`Arg::number_of_values(1)`]
+ ///
+ /// **WARNING**: When building your CLIs, consider the effects of allowing leading hyphens and
+ /// the user passing in a value that matches a valid short. For example `prog -opt -F` where
+ /// `-F` is supposed to be a value, yet `-F` is *also* a valid short for another arg. Care should
+ /// should be taken when designing these args. This is compounded by the ability to "stack"
+ /// short args. I.e. if `-val` is supposed to be a value, but `-v`, `-a`, and `-l` are all valid
+ /// shorts.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("pattern")
+ /// .allow_hyphen_values(true)
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("pat")
+ /// .allow_hyphen_values(true)
+ /// .takes_value(true)
+ /// .long("pattern"))
+ /// .get_matches_from(vec![
+ /// "prog", "--pattern", "-file"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("pat"), Some("-file"));
+ /// ```
+ ///
+ /// Not setting [`Arg::allow_hyphen_values(true)`] and supplying a value which starts with a
+ /// hyphen is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("pat")
+ /// .takes_value(true)
+ /// .long("pattern"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--pattern", "-file"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+ /// ```
+ /// [`Arg::allow_hyphen_values(true)`]: ./struct.Arg.html#method.allow_hyphen_values
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values
+ pub fn allow_hyphen_values(self, a: bool) -> Self {
+ if a {
+ self.set(ArgSettings::AllowLeadingHyphen)
+ } else {
+ self.unset(ArgSettings::AllowLeadingHyphen)
+ }
+ }
+ /// Sets an arg that override this arg's required setting. (i.e. this arg will be required
+ /// unless this other argument is present).
+ ///
+ /// **Pro Tip:** Using [`Arg::required_unless`] implies [`Arg::required`] and is therefore not
+ /// mandatory to also set.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .required_unless("debug")
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::required_unless(name)`] requires that the argument be used at runtime
+ /// *unless* `name` is present. In the following example, the required argument is *not*
+ /// provided, but it's not an error because the `unless` arg has been supplied.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required_unless("dbg")
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .arg(Arg::with_name("dbg")
+ /// .long("debug"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--debug"
+ /// ]);
+ ///
+ /// assert!(res.is_ok());
+ /// ```
+ ///
+ /// Setting [`Arg::required_unless(name)`] and *not* supplying `name` or this arg is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required_unless("dbg")
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .arg(Arg::with_name("dbg")
+ /// .long("debug"))
+ /// .get_matches_from_safe(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`Arg::required_unless`]: ./struct.Arg.html#method.required_unless
+ /// [`Arg::required`]: ./struct.Arg.html#method.required
+ /// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless
+ pub fn required_unless(mut self, name: &'a str) -> Self {
+ if let Some(ref mut vec) = self.b.r_unless {
+ vec.push(name);
+ } else {
+ self.b.r_unless = Some(vec![name]);
+ }
+ self.required(true)
+ }
+
+ /// Sets args that override this arg's required setting. (i.e. this arg will be required unless
+ /// all these other arguments are present).
+ ///
+ /// **NOTE:** If you wish for this argument to only be required if *one of* these args are
+ /// present see [`Arg::required_unless_one`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .required_unless_all(&["cfg", "dbg"])
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::required_unless_all(names)`] requires that the argument be used at runtime
+ /// *unless* *all* the args in `names` are present. In the following example, the required
+ /// argument is *not* provided, but it's not an error because all the `unless` args have been
+ /// supplied.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required_unless_all(&["dbg", "infile"])
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .arg(Arg::with_name("dbg")
+ /// .long("debug"))
+ /// .arg(Arg::with_name("infile")
+ /// .short("i")
+ /// .takes_value(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--debug", "-i", "file"
+ /// ]);
+ ///
+ /// assert!(res.is_ok());
+ /// ```
+ ///
+ /// Setting [`Arg::required_unless_all(names)`] and *not* supplying *all* of `names` or this
+ /// arg is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required_unless_all(&["dbg", "infile"])
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .arg(Arg::with_name("dbg")
+ /// .long("debug"))
+ /// .arg(Arg::with_name("infile")
+ /// .short("i")
+ /// .takes_value(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one
+ /// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all
+ pub fn required_unless_all(mut self, names: &[&'a str]) -> Self {
+ if let Some(ref mut vec) = self.b.r_unless {
+ for s in names {
+ vec.push(s);
+ }
+ } else {
+ self.b.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
+ }
+ self.setb(ArgSettings::RequiredUnlessAll);
+ self.required(true)
+ }
+
+ /// Sets args that override this arg's [required] setting. (i.e. this arg will be required
+ /// unless *at least one of* these other arguments are present).
+ ///
+ /// **NOTE:** If you wish for this argument to only be required if *all of* these args are
+ /// present see [`Arg::required_unless_all`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .required_unless_all(&["cfg", "dbg"])
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::required_unless_one(names)`] requires that the argument be used at runtime
+ /// *unless* *at least one of* the args in `names` are present. In the following example, the
+ /// required argument is *not* provided, but it's not an error because one the `unless` args
+ /// have been supplied.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required_unless_one(&["dbg", "infile"])
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .arg(Arg::with_name("dbg")
+ /// .long("debug"))
+ /// .arg(Arg::with_name("infile")
+ /// .short("i")
+ /// .takes_value(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--debug"
+ /// ]);
+ ///
+ /// assert!(res.is_ok());
+ /// ```
+ ///
+ /// Setting [`Arg::required_unless_one(names)`] and *not* supplying *at least one of* `names`
+ /// or this arg is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required_unless_one(&["dbg", "infile"])
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .arg(Arg::with_name("dbg")
+ /// .long("debug"))
+ /// .arg(Arg::with_name("infile")
+ /// .short("i")
+ /// .takes_value(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [required]: ./struct.Arg.html#method.required
+ /// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one
+ /// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all
+ pub fn required_unless_one(mut self, names: &[&'a str]) -> Self {
+ if let Some(ref mut vec) = self.b.r_unless {
+ for s in names {
+ vec.push(s);
+ }
+ } else {
+ self.b.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
+ }
+ self.required(true)
+ }
+
+ /// Sets a conflicting argument by name. I.e. when using this argument,
+ /// the following argument can't be present and vice versa.
+ ///
+ /// **NOTE:** Conflicting rules take precedence over being required by default. Conflict rules
+ /// only need to be set for one of the two arguments, they do not need to be set for each.
+ ///
+ /// **NOTE:** Defining a conflict is two-way, but does *not* need to defined for both arguments
+ /// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not need
+ /// need to also do B.conflicts_with(A))
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .conflicts_with("debug")
+ /// # ;
+ /// ```
+ ///
+ /// Setting conflicting argument, and having both arguments present at runtime is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .conflicts_with("debug")
+ /// .long("config"))
+ /// .arg(Arg::with_name("debug")
+ /// .long("debug"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--debug", "--config", "file.conf"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict);
+ /// ```
+ pub fn conflicts_with(mut self, name: &'a str) -> Self {
+ if let Some(ref mut vec) = self.b.blacklist {
+ vec.push(name);
+ } else {
+ self.b.blacklist = Some(vec![name]);
+ }
+ self
+ }
+
+ /// The same as [`Arg::conflicts_with`] but allows specifying multiple two-way conlicts per
+ /// argument.
+ ///
+ /// **NOTE:** Conflicting rules take precedence over being required by default. Conflict rules
+ /// only need to be set for one of the two arguments, they do not need to be set for each.
+ ///
+ /// **NOTE:** Defining a conflict is two-way, but does *not* need to defined for both arguments
+ /// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not need
+ /// need to also do B.conflicts_with(A))
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .conflicts_with_all(&["debug", "input"])
+ /// # ;
+ /// ```
+ ///
+ /// Setting conflicting argument, and having any of the arguments present at runtime with a
+ /// conflicting argument is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .conflicts_with_all(&["debug", "input"])
+ /// .long("config"))
+ /// .arg(Arg::with_name("debug")
+ /// .long("debug"))
+ /// .arg(Arg::with_name("input")
+ /// .index(1))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config", "file.conf", "file.txt"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict);
+ /// ```
+ /// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with
+ pub fn conflicts_with_all(mut self, names: &[&'a str]) -> Self {
+ if let Some(ref mut vec) = self.b.blacklist {
+ for s in names {
+ vec.push(s);
+ }
+ } else {
+ self.b.blacklist = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
+ }
+ self
+ }
+
+ /// Sets a overridable argument by name. I.e. this argument and the following argument
+ /// will override each other in POSIX style (whichever argument was specified at runtime
+ /// **last** "wins")
+ ///
+ /// **NOTE:** When an argument is overridden it is essentially as if it never was used, any
+ /// conflicts, requirements, etc. are evaluated **after** all "overrides" have been removed
+ ///
+ /// **WARNING:** Positional arguments cannot override themselves (or we would never be able
+ /// to advance to the next positional). If a positional agument lists itself as an override,
+ /// it is simply ignored.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::from_usage("-f, --flag 'some flag'")
+ /// .conflicts_with("debug"))
+ /// .arg(Arg::from_usage("-d, --debug 'other flag'"))
+ /// .arg(Arg::from_usage("-c, --color 'third flag'")
+ /// .overrides_with("flag"))
+ /// .get_matches_from(vec![
+ /// "prog", "-f", "-d", "-c"]);
+ /// // ^~~~~~~~~~~~^~~~~ flag is overridden by color
+ ///
+ /// assert!(m.is_present("color"));
+ /// assert!(m.is_present("debug")); // even though flag conflicts with debug, it's as if flag
+ /// // was never used because it was overridden with color
+ /// assert!(!m.is_present("flag"));
+ /// ```
+ /// Care must be taken when using this setting, and having an arg override with itself. This
+ /// is common practice when supporting things like shell aliases, config files, etc.
+ /// However, when combined with multiple values, it can get dicy.
+ /// Here is how clap handles such situations:
+ ///
+ /// When a flag overrides itself, it's as if the flag was only ever used once (essentially
+ /// preventing a "Unexpected multiple usage" error):
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("posix")
+ /// .arg(Arg::from_usage("--flag 'some flag'").overrides_with("flag"))
+ /// .get_matches_from(vec!["posix", "--flag", "--flag"]);
+ /// assert!(m.is_present("flag"));
+ /// assert_eq!(m.occurrences_of("flag"), 1);
+ /// ```
+ /// Making a arg `multiple(true)` and override itself is essentially meaningless. Therefore
+ /// clap ignores an override of self if it's a flag and it already accepts multiple occurrences.
+ ///
+ /// ```
+ /// # use clap::{App, Arg};
+ /// let m = App::new("posix")
+ /// .arg(Arg::from_usage("--flag... 'some flag'").overrides_with("flag"))
+ /// .get_matches_from(vec!["", "--flag", "--flag", "--flag", "--flag"]);
+ /// assert!(m.is_present("flag"));
+ /// assert_eq!(m.occurrences_of("flag"), 4);
+ /// ```
+ /// Now notice with options (which *do not* set `multiple(true)`), it's as if only the last
+ /// occurrence happened.
+ ///
+ /// ```
+ /// # use clap::{App, Arg};
+ /// let m = App::new("posix")
+ /// .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("opt"))
+ /// .get_matches_from(vec!["", "--opt=some", "--opt=other"]);
+ /// assert!(m.is_present("opt"));
+ /// assert_eq!(m.occurrences_of("opt"), 1);
+ /// assert_eq!(m.value_of("opt"), Some("other"));
+ /// ```
+ ///
+ /// Just like flags, options with `multiple(true)` set, will ignore the "override self" setting.
+ ///
+ /// ```
+ /// # use clap::{App, Arg};
+ /// let m = App::new("posix")
+ /// .arg(Arg::from_usage("--opt [val]... 'some option'")
+ /// .overrides_with("opt"))
+ /// .get_matches_from(vec!["", "--opt", "first", "over", "--opt", "other", "val"]);
+ /// assert!(m.is_present("opt"));
+ /// assert_eq!(m.occurrences_of("opt"), 2);
+ /// assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["first", "over", "other", "val"]);
+ /// ```
+ ///
+ /// A safe thing to do if you'd like to support an option which supports multiple values, but
+ /// also is "overridable" by itself, is to use `use_delimiter(false)` and *not* use
+ /// `multiple(true)` while telling users to seperate values with a comma (i.e. `val1,val2`)
+ ///
+ /// ```
+ /// # use clap::{App, Arg};
+ /// let m = App::new("posix")
+ /// .arg(Arg::from_usage("--opt [val] 'some option'")
+ /// .overrides_with("opt")
+ /// .use_delimiter(false))
+ /// .get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]);
+ /// assert!(m.is_present("opt"));
+ /// assert_eq!(m.occurrences_of("opt"), 1);
+ /// assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["one,two"]);
+ /// ```
+ pub fn overrides_with(mut self, name: &'a str) -> Self {
+ if let Some(ref mut vec) = self.b.overrides {
+ vec.push(name);
+ } else {
+ self.b.overrides = Some(vec![name]);
+ }
+ self
+ }
+
+ /// Sets multiple mutually overridable arguments by name. I.e. this argument and the following
+ /// argument will override each other in POSIX style (whichever argument was specified at
+ /// runtime **last** "wins")
+ ///
+ /// **NOTE:** When an argument is overridden it is essentially as if it never was used, any
+ /// conflicts, requirements, etc. are evaluated **after** all "overrides" have been removed
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::from_usage("-f, --flag 'some flag'")
+ /// .conflicts_with("color"))
+ /// .arg(Arg::from_usage("-d, --debug 'other flag'"))
+ /// .arg(Arg::from_usage("-c, --color 'third flag'")
+ /// .overrides_with_all(&["flag", "debug"]))
+ /// .get_matches_from(vec![
+ /// "prog", "-f", "-d", "-c"]);
+ /// // ^~~~~~^~~~~~~~~ flag and debug are overridden by color
+ ///
+ /// assert!(m.is_present("color")); // even though flag conflicts with color, it's as if flag
+ /// // and debug were never used because they were overridden
+ /// // with color
+ /// assert!(!m.is_present("debug"));
+ /// assert!(!m.is_present("flag"));
+ /// ```
+ pub fn overrides_with_all(mut self, names: &[&'a str]) -> Self {
+ if let Some(ref mut vec) = self.b.overrides {
+ for s in names {
+ vec.push(s);
+ }
+ } else {
+ self.b.overrides = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
+ }
+ self
+ }
+
+ /// Sets an argument by name that is required when this one is present I.e. when
+ /// using this argument, the following argument *must* be present.
+ ///
+ /// **NOTE:** [Conflicting] rules and [override] rules take precedence over being required
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .requires("input")
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::requires(name)`] requires that the argument be used at runtime if the
+ /// defining argument is used. If the defining argument isn't used, the other argument isn't
+ /// required
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .requires("input")
+ /// .long("config"))
+ /// .arg(Arg::with_name("input")
+ /// .index(1))
+ /// .get_matches_from_safe(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert!(res.is_ok()); // We didn't use cfg, so input wasn't required
+ /// ```
+ ///
+ /// Setting [`Arg::requires(name)`] and *not* supplying that argument is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .requires("input")
+ /// .long("config"))
+ /// .arg(Arg::with_name("input")
+ /// .index(1))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config", "file.conf"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
+ /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
+ /// [override]: ./struct.Arg.html#method.overrides_with
+ pub fn requires(mut self, name: &'a str) -> Self {
+ if let Some(ref mut vec) = self.b.requires {
+ vec.push((None, name));
+ } else {
+ let mut vec = vec![];
+ vec.push((None, name));
+ self.b.requires = Some(vec);
+ }
+ self
+ }
+
+ /// Allows a conditional requirement. The requirement will only become valid if this arg's value
+ /// equals `val`.
+ ///
+ /// **NOTE:** If using YAML the values should be laid out as follows
+ ///
+ /// ```yaml
+ /// requires_if:
+ /// - [val, arg]
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .requires_if("val", "arg")
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::requires_if(val, arg)`] requires that the `arg` be used at runtime if the
+ /// defining argument's value is equal to `val`. If the defining argument is anything other than
+ /// `val`, the other argument isn't required.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .requires_if("my.cfg", "other")
+ /// .long("config"))
+ /// .arg(Arg::with_name("other"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config", "some.cfg"
+ /// ]);
+ ///
+ /// assert!(res.is_ok()); // We didn't use --config=my.cfg, so other wasn't required
+ /// ```
+ ///
+ /// Setting [`Arg::requires_if(val, arg)`] and setting the value to `val` but *not* supplying
+ /// `arg` is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .requires_if("my.cfg", "input")
+ /// .long("config"))
+ /// .arg(Arg::with_name("input"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config", "my.cfg"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
+ /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
+ /// [override]: ./struct.Arg.html#method.overrides_with
+ pub fn requires_if(mut self, val: &'b str, arg: &'a str) -> Self {
+ if let Some(ref mut vec) = self.b.requires {
+ vec.push((Some(val), arg));
+ } else {
+ self.b.requires = Some(vec![(Some(val), arg)]);
+ }
+ self
+ }
+
+ /// Allows multiple conditional requirements. The requirement will only become valid if this arg's value
+ /// equals `val`.
+ ///
+ /// **NOTE:** If using YAML the values should be laid out as follows
+ ///
+ /// ```yaml
+ /// requires_if:
+ /// - [val, arg]
+ /// - [val2, arg2]
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .requires_ifs(&[
+ /// ("val", "arg"),
+ /// ("other_val", "arg2"),
+ /// ])
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::requires_ifs(&["val", "arg"])`] requires that the `arg` be used at runtime if the
+ /// defining argument's value is equal to `val`. If the defining argument's value is anything other
+ /// than `val`, `arg` isn't required.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .requires_ifs(&[
+ /// ("special.conf", "opt"),
+ /// ("other.conf", "other"),
+ /// ])
+ /// .long("config"))
+ /// .arg(Arg::with_name("opt")
+ /// .long("option")
+ /// .takes_value(true))
+ /// .arg(Arg::with_name("other"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config", "special.conf"
+ /// ]);
+ ///
+ /// assert!(res.is_err()); // We used --config=special.conf so --option <val> is required
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
+ /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
+ /// [override]: ./struct.Arg.html#method.overrides_with
+ pub fn requires_ifs(mut self, ifs: &[(&'b str, &'a str)]) -> Self {
+ if let Some(ref mut vec) = self.b.requires {
+ for &(val, arg) in ifs {
+ vec.push((Some(val), arg));
+ }
+ } else {
+ let mut vec = vec![];
+ for &(val, arg) in ifs {
+ vec.push((Some(val), arg));
+ }
+ self.b.requires = Some(vec);
+ }
+ self
+ }
+
+ /// Allows specifying that an argument is [required] conditionally. The requirement will only
+ /// become valid if the specified `arg`'s value equals `val`.
+ ///
+ /// **NOTE:** If using YAML the values should be laid out as follows
+ ///
+ /// ```yaml
+ /// required_if:
+ /// - [arg, val]
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .required_if("other_arg", "value")
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::required_if(arg, val)`] makes this arg required if the `arg` is used at
+ /// runtime and it's value is equal to `val`. If the `arg`'s value is anything other than `val`,
+ /// this argument isn't required.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .required_if("other", "special")
+ /// .long("config"))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .takes_value(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--other", "not-special"
+ /// ]);
+ ///
+ /// assert!(res.is_ok()); // We didn't use --other=special, so "cfg" wasn't required
+ /// ```
+ ///
+ /// Setting [`Arg::required_if(arg, val)`] and having `arg` used with a value of `val` but *not*
+ /// using this arg is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .required_if("other", "special")
+ /// .long("config"))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .takes_value(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--other", "special"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
+ /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
+ /// [required]: ./struct.Arg.html#method.required
+ pub fn required_if(mut self, arg: &'a str, val: &'b str) -> Self {
+ if let Some(ref mut vec) = self.r_ifs {
+ vec.push((arg, val));
+ } else {
+ self.r_ifs = Some(vec![(arg, val)]);
+ }
+ self
+ }
+
+ /// Allows specifying that an argument is [required] based on multiple conditions. The
+ /// conditions are set up in a `(arg, val)` style tuple. The requirement will only become valid
+ /// if one of the specified `arg`'s value equals it's corresponding `val`.
+ ///
+ /// **NOTE:** If using YAML the values should be laid out as follows
+ ///
+ /// ```yaml
+ /// required_if:
+ /// - [arg, val]
+ /// - [arg2, val2]
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .required_ifs(&[
+ /// ("extra", "val"),
+ /// ("option", "spec")
+ /// ])
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::required_ifs(&[(arg, val)])`] makes this arg required if any of the `arg`s
+ /// are used at runtime and it's corresponding value is equal to `val`. If the `arg`'s value is
+ /// anything other than `val`, this argument isn't required.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required_ifs(&[
+ /// ("extra", "val"),
+ /// ("option", "spec")
+ /// ])
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .arg(Arg::with_name("extra")
+ /// .takes_value(true)
+ /// .long("extra"))
+ /// .arg(Arg::with_name("option")
+ /// .takes_value(true)
+ /// .long("option"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--option", "other"
+ /// ]);
+ ///
+ /// assert!(res.is_ok()); // We didn't use --option=spec, or --extra=val so "cfg" isn't required
+ /// ```
+ ///
+ /// Setting [`Arg::required_ifs(&[(arg, val)])`] and having any of the `arg`s used with it's
+ /// value of `val` but *not* using this arg is an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .required_ifs(&[
+ /// ("extra", "val"),
+ /// ("option", "spec")
+ /// ])
+ /// .takes_value(true)
+ /// .long("config"))
+ /// .arg(Arg::with_name("extra")
+ /// .takes_value(true)
+ /// .long("extra"))
+ /// .arg(Arg::with_name("option")
+ /// .takes_value(true)
+ /// .long("option"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--option", "spec"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
+ /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
+ /// [required]: ./struct.Arg.html#method.required
+ pub fn required_ifs(mut self, ifs: &[(&'a str, &'b str)]) -> Self {
+ if let Some(ref mut vec) = self.r_ifs {
+ for r_if in ifs {
+ vec.push((r_if.0, r_if.1));
+ }
+ } else {
+ let mut vec = vec![];
+ for r_if in ifs {
+ vec.push((r_if.0, r_if.1));
+ }
+ self.r_ifs = Some(vec);
+ }
+ self
+ }
+
+ /// Sets multiple arguments by names that are required when this one is present I.e. when
+ /// using this argument, the following arguments *must* be present.
+ ///
+ /// **NOTE:** [Conflicting] rules and [override] rules take precedence over being required
+ /// by default.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::Arg;
+ /// Arg::with_name("config")
+ /// .requires_all(&["input", "output"])
+ /// # ;
+ /// ```
+ ///
+ /// Setting [`Arg::requires_all(&[arg, arg2])`] requires that all the arguments be used at
+ /// runtime if the defining argument is used. If the defining argument isn't used, the other
+ /// argument isn't required
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .requires("input")
+ /// .long("config"))
+ /// .arg(Arg::with_name("input")
+ /// .index(1))
+ /// .arg(Arg::with_name("output")
+ /// .index(2))
+ /// .get_matches_from_safe(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert!(res.is_ok()); // We didn't use cfg, so input and output weren't required
+ /// ```
+ ///
+ /// Setting [`Arg::requires_all(&[arg, arg2])`] and *not* supplying all the arguments is an
+ /// error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .takes_value(true)
+ /// .requires_all(&["input", "output"])
+ /// .long("config"))
+ /// .arg(Arg::with_name("input")
+ /// .index(1))
+ /// .arg(Arg::with_name("output")
+ /// .index(2))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config", "file.conf", "in.txt"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// // We didn't use output
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [Conflicting]: ./struct.Arg.html#method.conflicts_with
+ /// [override]: ./struct.Arg.html#method.overrides_with
+ /// [`Arg::requires_all(&[arg, arg2])`]: ./struct.Arg.html#method.requires_all
+ pub fn requires_all(mut self, names: &[&'a str]) -> Self {
+ if let Some(ref mut vec) = self.b.requires {
+ for s in names {
+ vec.push((None, s));
+ }
+ } else {
+ let mut vec = vec![];
+ for s in names {
+ vec.push((None, *s));
+ }
+ self.b.requires = Some(vec);
+ }
+ self
+ }
+
+ /// Specifies that the argument takes a value at run time.
+ ///
+ /// **NOTE:** values for arguments may be specified in any of the following methods
+ ///
+ /// * Using a space such as `-o value` or `--option value`
+ /// * Using an equals and no space such as `-o=value` or `--option=value`
+ /// * Use a short and no space such as `-ovalue`
+ ///
+ /// **NOTE:** By default, args which allow [multiple values] are delimited by commas, meaning
+ /// `--option=val1,val2,val3` is three values for the `--option` argument. If you wish to
+ /// change the delimiter to another character you can use [`Arg::value_delimiter(char)`],
+ /// alternatively you can turn delimiting values **OFF** by using [`Arg::use_delimiter(false)`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("config")
+ /// .takes_value(true)
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("mode")
+ /// .long("mode")
+ /// .takes_value(true))
+ /// .get_matches_from(vec![
+ /// "prog", "--mode", "fast"
+ /// ]);
+ ///
+ /// assert!(m.is_present("mode"));
+ /// assert_eq!(m.value_of("mode"), Some("fast"));
+ /// ```
+ /// [`Arg::value_delimiter(char)`]: ./struct.Arg.html#method.value_delimiter
+ /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter
+ /// [multiple values]: ./struct.Arg.html#method.multiple
+ pub fn takes_value(self, tv: bool) -> Self {
+ if tv {
+ self.set(ArgSettings::TakesValue)
+ } else {
+ self.unset(ArgSettings::TakesValue)
+ }
+ }
+
+ /// Specifies if the possible values of an argument should be displayed in the help text or
+ /// not. Defaults to `false` (i.e. show possible values)
+ ///
+ /// This is useful for args with many values, or ones which are explained elsewhere in the
+ /// help text.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("config")
+ /// .hide_possible_values(true)
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("mode")
+ /// .long("mode")
+ /// .possible_values(&["fast", "slow"])
+ /// .takes_value(true)
+ /// .hide_possible_values(true));
+ ///
+ /// ```
+ ///
+ /// If we were to run the above program with `--help` the `[values: fast, slow]` portion of
+ /// the help text would be omitted.
+ pub fn hide_possible_values(self, hide: bool) -> Self {
+ if hide {
+ self.set(ArgSettings::HidePossibleValues)
+ } else {
+ self.unset(ArgSettings::HidePossibleValues)
+ }
+ }
+
+ /// Specifies if the default value of an argument should be displayed in the help text or
+ /// not. Defaults to `false` (i.e. show default value)
+ ///
+ /// This is useful when default behavior of an arg is explained elsewhere in the help text.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("config")
+ /// .hide_default_value(true)
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("connect")
+ /// .arg(Arg::with_name("host")
+ /// .long("host")
+ /// .default_value("localhost")
+ /// .hide_default_value(true));
+ ///
+ /// ```
+ ///
+ /// If we were to run the above program with `--help` the `[default: localhost]` portion of
+ /// the help text would be omitted.
+ pub fn hide_default_value(self, hide: bool) -> Self {
+ if hide {
+ self.set(ArgSettings::HideDefaultValue)
+ } else {
+ self.unset(ArgSettings::HideDefaultValue)
+ }
+ }
+
+ /// Specifies the index of a positional argument **starting at** 1.
+ ///
+ /// **NOTE:** The index refers to position according to **other positional argument**. It does
+ /// not define position in the argument list as a whole.
+ ///
+ /// **NOTE:** If no [`Arg::short`], or [`Arg::long`] have been defined, you can optionally
+ /// leave off the `index` method, and the index will be assigned in order of evaluation.
+ /// Utilizing the `index` method allows for setting indexes out of order
+ ///
+ /// **NOTE:** When utilized with [`Arg::multiple(true)`], only the **last** positional argument
+ /// may be defined as multiple (i.e. with the highest index)
+ ///
+ /// # Panics
+ ///
+ /// Although not in this method directly, [`App`] will [`panic!`] if indexes are skipped (such
+ /// as defining `index(1)` and `index(3)` but not `index(2)`, or a positional argument is
+ /// defined as multiple and is not the highest index
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("config")
+ /// .index(1)
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("mode")
+ /// .index(1))
+ /// .arg(Arg::with_name("debug")
+ /// .long("debug"))
+ /// .get_matches_from(vec![
+ /// "prog", "--debug", "fast"
+ /// ]);
+ ///
+ /// assert!(m.is_present("mode"));
+ /// assert_eq!(m.value_of("mode"), Some("fast")); // notice index(1) means "first positional"
+ /// // *not* first argument
+ /// ```
+ /// [`Arg::short`]: ./struct.Arg.html#method.short
+ /// [`Arg::long`]: ./struct.Arg.html#method.long
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ /// [`App`]: ./struct.App.html
+ /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
+ pub fn index(mut self, idx: u64) -> Self {
+ self.index = Some(idx);
+ self
+ }
+
+ /// Specifies that the argument may appear more than once. For flags, this results
+ /// in the number of occurrences of the flag being recorded. For example `-ddd` or `-d -d -d`
+ /// would count as three occurrences. For options there is a distinct difference in multiple
+ /// occurrences vs multiple values.
+ ///
+ /// For example, `--opt val1 val2` is one occurrence, but two values. Whereas
+ /// `--opt val1 --opt val2` is two occurrences.
+ ///
+ /// **WARNING:**
+ ///
+ /// Setting `multiple(true)` for an [option] with no other details, allows multiple values
+ /// **and** multiple occurrences because it isn't possible to have more occurrences than values
+ /// for options. Because multiple values are allowed, `--option val1 val2 val3` is perfectly
+ /// valid, be careful when designing a CLI where positional arguments are expected after a
+ /// option which accepts multiple values, as `clap` will continue parsing *values* until it
+ /// reaches the max or specific number of values defined, or another flag or option.
+ ///
+ /// **Pro Tip**:
+ ///
+ /// It's possible to define an option which allows multiple occurrences, but only one value per
+ /// occurrence. To do this use [`Arg::number_of_values(1)`] in coordination with
+ /// [`Arg::multiple(true)`].
+ ///
+ /// **WARNING:**
+ ///
+ /// When using args with `multiple(true)` on [options] or [positionals] (i.e. those args that
+ /// accept values) and [subcommands], one needs to consider the possibility of an argument value
+ /// being the same as a valid subcommand. By default `clap` will parse the argument in question
+ /// as a value *only if* a value is possible at that moment. Otherwise it will be parsed as a
+ /// subcommand. In effect, this means using `multiple(true)` with no additional parameters and
+ /// a possible value that coincides with a subcommand name, the subcommand cannot be called
+ /// unless another argument is passed first.
+ ///
+ /// As an example, consider a CLI with an option `--ui-paths=<paths>...` and subcommand `signer`
+ ///
+ /// The following would be parsed as values to `--ui-paths`.
+ ///
+ /// ```notrust
+ /// $ program --ui-paths path1 path2 signer
+ /// ```
+ ///
+ /// This is because `--ui-paths` accepts multiple values. `clap` will continue parsing values
+ /// until another argument is reached and it knows `--ui-paths` is done.
+ ///
+ /// By adding additional parameters to `--ui-paths` we can solve this issue. Consider adding
+ /// [`Arg::number_of_values(1)`] as discussed above. The following are all valid, and `signer`
+ /// is parsed as both a subcommand and a value in the second case.
+ ///
+ /// ```notrust
+ /// $ program --ui-paths path1 signer
+ /// $ program --ui-paths path1 --ui-paths signer signer
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("debug")
+ /// .short("d")
+ /// .multiple(true)
+ /// # ;
+ /// ```
+ /// An example with flags
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("verbose")
+ /// .multiple(true)
+ /// .short("v"))
+ /// .get_matches_from(vec![
+ /// "prog", "-v", "-v", "-v" // note, -vvv would have same result
+ /// ]);
+ ///
+ /// assert!(m.is_present("verbose"));
+ /// assert_eq!(m.occurrences_of("verbose"), 3);
+ /// ```
+ ///
+ /// An example with options
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .multiple(true)
+ /// .takes_value(true)
+ /// .short("F"))
+ /// .get_matches_from(vec![
+ /// "prog", "-F", "file1", "file2", "file3"
+ /// ]);
+ ///
+ /// assert!(m.is_present("file"));
+ /// assert_eq!(m.occurrences_of("file"), 1); // notice only one occurrence
+ /// let files: Vec<_> = m.values_of("file").unwrap().collect();
+ /// assert_eq!(files, ["file1", "file2", "file3"]);
+ /// ```
+ /// This is functionally equivalent to the example above
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .multiple(true)
+ /// .takes_value(true)
+ /// .short("F"))
+ /// .get_matches_from(vec![
+ /// "prog", "-F", "file1", "-F", "file2", "-F", "file3"
+ /// ]);
+ /// let files: Vec<_> = m.values_of("file").unwrap().collect();
+ /// assert_eq!(files, ["file1", "file2", "file3"]);
+ ///
+ /// assert!(m.is_present("file"));
+ /// assert_eq!(m.occurrences_of("file"), 3); // Notice 3 occurrences
+ /// let files: Vec<_> = m.values_of("file").unwrap().collect();
+ /// assert_eq!(files, ["file1", "file2", "file3"]);
+ /// ```
+ ///
+ /// A common mistake is to define an option which allows multiples, and a positional argument
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .multiple(true)
+ /// .takes_value(true)
+ /// .short("F"))
+ /// .arg(Arg::with_name("word")
+ /// .index(1))
+ /// .get_matches_from(vec![
+ /// "prog", "-F", "file1", "file2", "file3", "word"
+ /// ]);
+ ///
+ /// assert!(m.is_present("file"));
+ /// let files: Vec<_> = m.values_of("file").unwrap().collect();
+ /// assert_eq!(files, ["file1", "file2", "file3", "word"]); // wait...what?!
+ /// assert!(!m.is_present("word")); // but we clearly used word!
+ /// ```
+ /// The problem is clap doesn't know when to stop parsing values for "files". This is further
+ /// compounded by if we'd said `word -F file1 file2` it would have worked fine, so it would
+ /// appear to only fail sometimes...not good!
+ ///
+ /// A solution for the example above is to specify that `-F` only accepts one value, but is
+ /// allowed to appear multiple times
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .multiple(true)
+ /// .takes_value(true)
+ /// .number_of_values(1)
+ /// .short("F"))
+ /// .arg(Arg::with_name("word")
+ /// .index(1))
+ /// .get_matches_from(vec![
+ /// "prog", "-F", "file1", "-F", "file2", "-F", "file3", "word"
+ /// ]);
+ ///
+ /// assert!(m.is_present("file"));
+ /// let files: Vec<_> = m.values_of("file").unwrap().collect();
+ /// assert_eq!(files, ["file1", "file2", "file3"]);
+ /// assert!(m.is_present("word"));
+ /// assert_eq!(m.value_of("word"), Some("word"));
+ /// ```
+ /// As a final example, notice if we define [`Arg::number_of_values(1)`] and try to run the
+ /// problem example above, it would have been a runtime error with a pretty message to the
+ /// user :)
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .multiple(true)
+ /// .takes_value(true)
+ /// .number_of_values(1)
+ /// .short("F"))
+ /// .arg(Arg::with_name("word")
+ /// .index(1))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "-F", "file1", "file2", "file3", "word"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+ /// ```
+ /// [option]: ./struct.Arg.html#method.takes_value
+ /// [options]: ./struct.Arg.html#method.takes_value
+ /// [subcommands]: ./struct.SubCommand.html
+ /// [positionals]: ./struct.Arg.html#method.index
+ /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ pub fn multiple(self, multi: bool) -> Self {
+ if multi {
+ self.set(ArgSettings::Multiple)
+ } else {
+ self.unset(ArgSettings::Multiple)
+ }
+ }
+
+ /// Specifies a value that *stops* parsing multiple values of a give argument. By default when
+ /// one sets [`multiple(true)`] on an argument, clap will continue parsing values for that
+ /// argument until it reaches another valid argument, or one of the other more specific settings
+ /// for multiple values is used (such as [`min_values`], [`max_values`] or
+ /// [`number_of_values`]).
+ ///
+ /// **NOTE:** This setting only applies to [options] and [positional arguments]
+ ///
+ /// **NOTE:** When the terminator is passed in on the command line, it is **not** stored as one
+ /// of the values
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("vals")
+ /// .takes_value(true)
+ /// .multiple(true)
+ /// .value_terminator(";")
+ /// # ;
+ /// ```
+ /// The following example uses two arguments, a sequence of commands, and the location in which
+ /// to perform them
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cmds")
+ /// .multiple(true)
+ /// .allow_hyphen_values(true)
+ /// .value_terminator(";"))
+ /// .arg(Arg::with_name("location"))
+ /// .get_matches_from(vec![
+ /// "prog", "find", "-type", "f", "-name", "special", ";", "/home/clap"
+ /// ]);
+ /// let cmds: Vec<_> = m.values_of("cmds").unwrap().collect();
+ /// assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]);
+ /// assert_eq!(m.value_of("location"), Some("/home/clap"));
+ /// ```
+ /// [options]: ./struct.Arg.html#method.takes_value
+ /// [positional arguments]: ./struct.Arg.html#method.index
+ /// [`multiple(true)`]: ./struct.Arg.html#method.multiple
+ /// [`min_values`]: ./struct.Arg.html#method.min_values
+ /// [`number_of_values`]: ./struct.Arg.html#method.number_of_values
+ /// [`max_values`]: ./struct.Arg.html#method.max_values
+ pub fn value_terminator(mut self, term: &'b str) -> Self {
+ self.setb(ArgSettings::TakesValue);
+ self.v.terminator = Some(term);
+ self
+ }
+
+ /// Specifies that an argument can be matched to all child [`SubCommand`]s.
+ ///
+ /// **NOTE:** Global arguments *only* propagate down, **not** up (to parent commands), however
+ /// their values once a user uses them will be propagated back up to parents. In effect, this
+ /// means one should *define* all global arguments at the top level, however it doesn't matter
+ /// where the user *uses* the global argument.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("debug")
+ /// .short("d")
+ /// .global(true)
+ /// # ;
+ /// ```
+ ///
+ /// For example, assume an application with two subcommands, and you'd like to define a
+ /// `--verbose` flag that can be called on any of the subcommands and parent, but you don't
+ /// want to clutter the source with three duplicate [`Arg`] definitions.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, SubCommand};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("verb")
+ /// .long("verbose")
+ /// .short("v")
+ /// .global(true))
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .subcommand(SubCommand::with_name("do-stuff"))
+ /// .get_matches_from(vec![
+ /// "prog", "do-stuff", "--verbose"
+ /// ]);
+ ///
+ /// assert_eq!(m.subcommand_name(), Some("do-stuff"));
+ /// let sub_m = m.subcommand_matches("do-stuff").unwrap();
+ /// assert!(sub_m.is_present("verb"));
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [required]: ./struct.Arg.html#method.required
+ /// [`ArgMatches`]: ./struct.ArgMatches.html
+ /// [`ArgMatches::is_present("flag")`]: ./struct.ArgMatches.html#method.is_present
+ /// [`Arg`]: ./struct.Arg.html
+ pub fn global(self, g: bool) -> Self {
+ if g {
+ self.set(ArgSettings::Global)
+ } else {
+ self.unset(ArgSettings::Global)
+ }
+ }
+
+ /// Allows an argument to accept explicitly empty values. An empty value must be specified at
+ /// the command line with an explicit `""`, or `''`
+ ///
+ /// **NOTE:** Defaults to `true` (Explicitly empty values are allowed)
+ ///
+ /// **NOTE:** Implicitly sets [`Arg::takes_value(true)`] when set to `false`
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("file")
+ /// .long("file")
+ /// .empty_values(false)
+ /// # ;
+ /// ```
+ /// The default is to allow empty values, such as `--option ""` would be an empty value. But
+ /// we can change to make empty values become an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config")
+ /// .short("v")
+ /// .empty_values(false))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--config="
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
+ /// ```
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ pub fn empty_values(mut self, ev: bool) -> Self {
+ if ev {
+ self.set(ArgSettings::EmptyValues)
+ } else {
+ self = self.set(ArgSettings::TakesValue);
+ self.unset(ArgSettings::EmptyValues)
+ }
+ }
+
+ /// Hides an argument from help message output.
+ ///
+ /// **NOTE:** Implicitly sets [`Arg::hidden_short_help(true)`] and [`Arg::hidden_long_help(true)`]
+ /// when set to true
+ ///
+ /// **NOTE:** This does **not** hide the argument from usage strings on error
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("debug")
+ /// .hidden(true)
+ /// # ;
+ /// ```
+ /// Setting `hidden(true)` will hide the argument when displaying help text
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config")
+ /// .hidden(true)
+ /// .help("Some help text describing the --config arg"))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ ///
+ /// The above example displays
+ ///
+ /// ```notrust
+ /// helptest
+ ///
+ /// USAGE:
+ /// helptest [FLAGS]
+ ///
+ /// FLAGS:
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ /// ```
+ /// [`Arg::hidden_short_help(true)`]: ./struct.Arg.html#method.hidden_short_help
+ /// [`Arg::hidden_long_help(true)`]: ./struct.Arg.html#method.hidden_long_help
+ pub fn hidden(self, h: bool) -> Self {
+ if h {
+ self.set(ArgSettings::Hidden)
+ } else {
+ self.unset(ArgSettings::Hidden)
+ }
+ }
+
+ /// Specifies a list of possible values for this argument. At runtime, `clap` verifies that
+ /// only one of the specified values was used, or fails with an error message.
+ ///
+ /// **NOTE:** This setting only applies to [options] and [positional arguments]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("mode")
+ /// .takes_value(true)
+ /// .possible_values(&["fast", "slow", "medium"])
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("mode")
+ /// .long("mode")
+ /// .takes_value(true)
+ /// .possible_values(&["fast", "slow", "medium"]))
+ /// .get_matches_from(vec![
+ /// "prog", "--mode", "fast"
+ /// ]);
+ /// assert!(m.is_present("mode"));
+ /// assert_eq!(m.value_of("mode"), Some("fast"));
+ /// ```
+ ///
+ /// The next example shows a failed parse from using a value which wasn't defined as one of the
+ /// possible values.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("mode")
+ /// .long("mode")
+ /// .takes_value(true)
+ /// .possible_values(&["fast", "slow", "medium"]))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--mode", "wrong"
+ /// ]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::InvalidValue);
+ /// ```
+ /// [options]: ./struct.Arg.html#method.takes_value
+ /// [positional arguments]: ./struct.Arg.html#method.index
+ pub fn possible_values(mut self, names: &[&'b str]) -> Self {
+ if let Some(ref mut vec) = self.v.possible_vals {
+ for s in names {
+ vec.push(s);
+ }
+ } else {
+ self.v.possible_vals = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
+ }
+ self
+ }
+
+ /// Specifies a possible value for this argument, one at a time. At runtime, `clap` verifies
+ /// that only one of the specified values was used, or fails with error message.
+ ///
+ /// **NOTE:** This setting only applies to [options] and [positional arguments]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("mode")
+ /// .takes_value(true)
+ /// .possible_value("fast")
+ /// .possible_value("slow")
+ /// .possible_value("medium")
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("mode")
+ /// .long("mode")
+ /// .takes_value(true)
+ /// .possible_value("fast")
+ /// .possible_value("slow")
+ /// .possible_value("medium"))
+ /// .get_matches_from(vec![
+ /// "prog", "--mode", "fast"
+ /// ]);
+ /// assert!(m.is_present("mode"));
+ /// assert_eq!(m.value_of("mode"), Some("fast"));
+ /// ```
+ ///
+ /// The next example shows a failed parse from using a value which wasn't defined as one of the
+ /// possible values.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("mode")
+ /// .long("mode")
+ /// .takes_value(true)
+ /// .possible_value("fast")
+ /// .possible_value("slow")
+ /// .possible_value("medium"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "--mode", "wrong"
+ /// ]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::InvalidValue);
+ /// ```
+ /// [options]: ./struct.Arg.html#method.takes_value
+ /// [positional arguments]: ./struct.Arg.html#method.index
+ pub fn possible_value(mut self, name: &'b str) -> Self {
+ if let Some(ref mut vec) = self.v.possible_vals {
+ vec.push(name);
+ } else {
+ self.v.possible_vals = Some(vec![name]);
+ }
+ self
+ }
+
+ /// When used with [`Arg::possible_values`] it allows the argument value to pass validation even if
+ /// the case differs from that of the specified `possible_value`.
+ ///
+ /// **Pro Tip:** Use this setting with [`arg_enum!`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// # use std::ascii::AsciiExt;
+ /// let m = App::new("pv")
+ /// .arg(Arg::with_name("option")
+ /// .long("--option")
+ /// .takes_value(true)
+ /// .possible_value("test123")
+ /// .case_insensitive(true))
+ /// .get_matches_from(vec![
+ /// "pv", "--option", "TeSt123",
+ /// ]);
+ ///
+ /// assert!(m.value_of("option").unwrap().eq_ignore_ascii_case("test123"));
+ /// ```
+ ///
+ /// This setting also works when multiple values can be defined:
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("pv")
+ /// .arg(Arg::with_name("option")
+ /// .short("-o")
+ /// .long("--option")
+ /// .takes_value(true)
+ /// .possible_value("test123")
+ /// .possible_value("test321")
+ /// .multiple(true)
+ /// .case_insensitive(true))
+ /// .get_matches_from(vec![
+ /// "pv", "--option", "TeSt123", "teST123", "tESt321"
+ /// ]);
+ ///
+ /// let matched_vals = m.values_of("option").unwrap().collect::<Vec<_>>();
+ /// assert_eq!(&*matched_vals, &["TeSt123", "teST123", "tESt321"]);
+ /// ```
+ /// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.possible_values
+ /// [`arg_enum!`]: ./macro.arg_enum.html
+ pub fn case_insensitive(self, ci: bool) -> Self {
+ if ci {
+ self.set(ArgSettings::CaseInsensitive)
+ } else {
+ self.unset(ArgSettings::CaseInsensitive)
+ }
+ }
+
+ /// Specifies the name of the [`ArgGroup`] the argument belongs to.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("debug")
+ /// .long("debug")
+ /// .group("mode")
+ /// # ;
+ /// ```
+ ///
+ /// Multiple arguments can be a member of a single group and then the group checked as if it
+ /// was one of said arguments.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("debug")
+ /// .long("debug")
+ /// .group("mode"))
+ /// .arg(Arg::with_name("verbose")
+ /// .long("verbose")
+ /// .group("mode"))
+ /// .get_matches_from(vec![
+ /// "prog", "--debug"
+ /// ]);
+ /// assert!(m.is_present("mode"));
+ /// ```
+ /// [`ArgGroup`]: ./struct.ArgGroup.html
+ pub fn group(mut self, name: &'a str) -> Self {
+ if let Some(ref mut vec) = self.b.groups {
+ vec.push(name);
+ } else {
+ self.b.groups = Some(vec![name]);
+ }
+ self
+ }
+
+ /// Specifies the names of multiple [`ArgGroup`]'s the argument belongs to.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("debug")
+ /// .long("debug")
+ /// .groups(&["mode", "verbosity"])
+ /// # ;
+ /// ```
+ ///
+ /// Arguments can be members of multiple groups and then the group checked as if it
+ /// was one of said arguments.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("debug")
+ /// .long("debug")
+ /// .groups(&["mode", "verbosity"]))
+ /// .arg(Arg::with_name("verbose")
+ /// .long("verbose")
+ /// .groups(&["mode", "verbosity"]))
+ /// .get_matches_from(vec![
+ /// "prog", "--debug"
+ /// ]);
+ /// assert!(m.is_present("mode"));
+ /// assert!(m.is_present("verbosity"));
+ /// ```
+ /// [`ArgGroup`]: ./struct.ArgGroup.html
+ pub fn groups(mut self, names: &[&'a str]) -> Self {
+ if let Some(ref mut vec) = self.b.groups {
+ for s in names {
+ vec.push(s);
+ }
+ } else {
+ self.b.groups = Some(names.into_iter().map(|s| *s).collect::<Vec<_>>());
+ }
+ self
+ }
+
+ /// Specifies how many values are required to satisfy this argument. For example, if you had a
+ /// `-f <file>` argument where you wanted exactly 3 'files' you would set
+ /// `.number_of_values(3)`, and this argument wouldn't be satisfied unless the user provided
+ /// 3 and only 3 values.
+ ///
+ /// **NOTE:** Does *not* require [`Arg::multiple(true)`] to be set. Setting
+ /// [`Arg::multiple(true)`] would allow `-f <file> <file> <file> -f <file> <file> <file>` where
+ /// as *not* setting [`Arg::multiple(true)`] would only allow one occurrence of this argument.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("file")
+ /// .short("f")
+ /// .number_of_values(3)
+ /// # ;
+ /// ```
+ ///
+ /// Not supplying the correct number of values is an error
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .takes_value(true)
+ /// .number_of_values(2)
+ /// .short("F"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "-F", "file1"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::WrongNumberOfValues);
+ /// ```
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ pub fn number_of_values(mut self, qty: u64) -> Self {
+ self.setb(ArgSettings::TakesValue);
+ self.v.num_vals = Some(qty);
+ self
+ }
+
+ /// Allows one to perform a custom validation on the argument value. You provide a closure
+ /// which accepts a [`String`] value, and return a [`Result`] where the [`Err(String)`] is a
+ /// message displayed to the user.
+ ///
+ /// **NOTE:** The error message does *not* need to contain the `error:` portion, only the
+ /// message as all errors will appear as
+ /// `error: Invalid value for '<arg>': <YOUR MESSAGE>` where `<arg>` is replaced by the actual
+ /// arg, and `<YOUR MESSAGE>` is the `String` you return as the error.
+ ///
+ /// **NOTE:** There is a small performance hit for using validators, as they are implemented
+ /// with [`Rc`] pointers. And the value to be checked will be allocated an extra time in order
+ /// to to be passed to the closure. This performance hit is extremely minimal in the grand
+ /// scheme of things.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// fn has_at(v: String) -> Result<(), String> {
+ /// if v.contains("@") { return Ok(()); }
+ /// Err(String::from("The value did not contain the required @ sigil"))
+ /// }
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .index(1)
+ /// .validator(has_at))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "some@file"
+ /// ]);
+ /// assert!(res.is_ok());
+ /// assert_eq!(res.unwrap().value_of("file"), Some("some@file"));
+ /// ```
+ /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
+ /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
+ /// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
+ /// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html
+ pub fn validator<F>(mut self, f: F) -> Self
+ where
+ F: Fn(String) -> Result<(), String> + 'static,
+ {
+ self.v.validator = Some(Rc::new(f));
+ self
+ }
+
+ /// Works identically to Validator but is intended to be used with values that could
+ /// contain non UTF-8 formatted strings.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```rust")]
+ /// # use clap::{App, Arg};
+ /// # use std::ffi::{OsStr, OsString};
+ /// # use std::os::unix::ffi::OsStrExt;
+ /// fn has_ampersand(v: &OsStr) -> Result<(), OsString> {
+ /// if v.as_bytes().iter().any(|b| *b == b'&') { return Ok(()); }
+ /// Err(OsString::from("The value did not contain the required & sigil"))
+ /// }
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .index(1)
+ /// .validator_os(has_ampersand))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "Fish & chips"
+ /// ]);
+ /// assert!(res.is_ok());
+ /// assert_eq!(res.unwrap().value_of("file"), Some("Fish & chips"));
+ /// ```
+ /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
+ /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
+ /// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html
+ /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
+ /// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
+ /// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html
+ pub fn validator_os<F>(mut self, f: F) -> Self
+ where
+ F: Fn(&OsStr) -> Result<(), OsString> + 'static,
+ {
+ self.v.validator_os = Some(Rc::new(f));
+ self
+ }
+
+ /// Specifies the *maximum* number of values are for this argument. For example, if you had a
+ /// `-f <file>` argument where you wanted up to 3 'files' you would set `.max_values(3)`, and
+ /// this argument would be satisfied if the user provided, 1, 2, or 3 values.
+ ///
+ /// **NOTE:** This does *not* implicitly set [`Arg::multiple(true)`]. This is because
+ /// `-o val -o val` is multiple occurrences but a single value and `-o val1 val2` is a single
+ /// occurrence with multiple values. For positional arguments this **does** set
+ /// [`Arg::multiple(true)`] because there is no way to determine the difference between multiple
+ /// occurrences and multiple values.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("file")
+ /// .short("f")
+ /// .max_values(3)
+ /// # ;
+ /// ```
+ ///
+ /// Supplying less than the maximum number of values is allowed
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .takes_value(true)
+ /// .max_values(3)
+ /// .short("F"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "-F", "file1", "file2"
+ /// ]);
+ ///
+ /// assert!(res.is_ok());
+ /// let m = res.unwrap();
+ /// let files: Vec<_> = m.values_of("file").unwrap().collect();
+ /// assert_eq!(files, ["file1", "file2"]);
+ /// ```
+ ///
+ /// Supplying more than the maximum number of values is an error
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .takes_value(true)
+ /// .max_values(2)
+ /// .short("F"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "-F", "file1", "file2", "file3"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::TooManyValues);
+ /// ```
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ pub fn max_values(mut self, qty: u64) -> Self {
+ self.setb(ArgSettings::TakesValue);
+ self.v.max_vals = Some(qty);
+ self
+ }
+
+ /// Specifies the *minimum* number of values for this argument. For example, if you had a
+ /// `-f <file>` argument where you wanted at least 2 'files' you would set
+ /// `.min_values(2)`, and this argument would be satisfied if the user provided, 2 or more
+ /// values.
+ ///
+ /// **NOTE:** This does not implicitly set [`Arg::multiple(true)`]. This is because
+ /// `-o val -o val` is multiple occurrences but a single value and `-o val1 val2` is a single
+ /// occurrence with multiple values. For positional arguments this **does** set
+ /// [`Arg::multiple(true)`] because there is no way to determine the difference between multiple
+ /// occurrences and multiple values.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("file")
+ /// .short("f")
+ /// .min_values(3)
+ /// # ;
+ /// ```
+ ///
+ /// Supplying more than the minimum number of values is allowed
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .takes_value(true)
+ /// .min_values(2)
+ /// .short("F"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "-F", "file1", "file2", "file3"
+ /// ]);
+ ///
+ /// assert!(res.is_ok());
+ /// let m = res.unwrap();
+ /// let files: Vec<_> = m.values_of("file").unwrap().collect();
+ /// assert_eq!(files, ["file1", "file2", "file3"]);
+ /// ```
+ ///
+ /// Supplying less than the minimum number of values is an error
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("file")
+ /// .takes_value(true)
+ /// .min_values(2)
+ /// .short("F"))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "-F", "file1"
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::TooFewValues);
+ /// ```
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ pub fn min_values(mut self, qty: u64) -> Self {
+ self.v.min_vals = Some(qty);
+ self.set(ArgSettings::TakesValue)
+ }
+
+ /// Specifies whether or not an argument should allow grouping of multiple values via a
+ /// delimiter. I.e. should `--option=val1,val2,val3` be parsed as three values (`val1`, `val2`,
+ /// and `val3`) or as a single value (`val1,val2,val3`). Defaults to using `,` (comma) as the
+ /// value delimiter for all arguments that accept values (options and positional arguments)
+ ///
+ /// **NOTE:** The default is `false`. When set to `true` the default [`Arg::value_delimiter`]
+ /// is the comma `,`.
+ ///
+ /// # Examples
+ ///
+ /// The following example shows the default behavior.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let delims = App::new("prog")
+ /// .arg(Arg::with_name("option")
+ /// .long("option")
+ /// .use_delimiter(true)
+ /// .takes_value(true))
+ /// .get_matches_from(vec![
+ /// "prog", "--option=val1,val2,val3",
+ /// ]);
+ ///
+ /// assert!(delims.is_present("option"));
+ /// assert_eq!(delims.occurrences_of("option"), 1);
+ /// assert_eq!(delims.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+ /// ```
+ /// The next example shows the difference when turning delimiters off. This is the default
+ /// behavior
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let nodelims = App::new("prog")
+ /// .arg(Arg::with_name("option")
+ /// .long("option")
+ /// .use_delimiter(false)
+ /// .takes_value(true))
+ /// .get_matches_from(vec![
+ /// "prog", "--option=val1,val2,val3",
+ /// ]);
+ ///
+ /// assert!(nodelims.is_present("option"));
+ /// assert_eq!(nodelims.occurrences_of("option"), 1);
+ /// assert_eq!(nodelims.value_of("option").unwrap(), "val1,val2,val3");
+ /// ```
+ /// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter
+ pub fn use_delimiter(mut self, d: bool) -> Self {
+ if d {
+ if self.v.val_delim.is_none() {
+ self.v.val_delim = Some(',');
+ }
+ self.setb(ArgSettings::TakesValue);
+ self.setb(ArgSettings::UseValueDelimiter);
+ self.unset(ArgSettings::ValueDelimiterNotSet)
+ } else {
+ self.v.val_delim = None;
+ self.unsetb(ArgSettings::UseValueDelimiter);
+ self.unset(ArgSettings::ValueDelimiterNotSet)
+ }
+ }
+
+ /// Specifies that *multiple values* may only be set using the delimiter. This means if an
+ /// if an option is encountered, and no delimiter is found, it automatically assumed that no
+ /// additional values for that option follow. This is unlike the default, where it is generally
+ /// assumed that more values will follow regardless of whether or not a delimiter is used.
+ ///
+ /// **NOTE:** The default is `false`.
+ ///
+ /// **NOTE:** Setting this to true implies [`Arg::use_delimiter(true)`]
+ ///
+ /// **NOTE:** It's a good idea to inform the user that use of a delimiter is required, either
+ /// through help text or other means.
+ ///
+ /// # Examples
+ ///
+ /// These examples demonstrate what happens when `require_delimiter(true)` is used. Notice
+ /// everything works in this first example, as we use a delimiter, as expected.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let delims = App::new("prog")
+ /// .arg(Arg::with_name("opt")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .multiple(true)
+ /// .require_delimiter(true))
+ /// .get_matches_from(vec![
+ /// "prog", "-o", "val1,val2,val3",
+ /// ]);
+ ///
+ /// assert!(delims.is_present("opt"));
+ /// assert_eq!(delims.values_of("opt").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+ /// ```
+ /// In this next example, we will *not* use a delimiter. Notice it's now an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("opt")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .multiple(true)
+ /// .require_delimiter(true))
+ /// .get_matches_from_safe(vec![
+ /// "prog", "-o", "val1", "val2", "val3",
+ /// ]);
+ ///
+ /// assert!(res.is_err());
+ /// let err = res.unwrap_err();
+ /// assert_eq!(err.kind, ErrorKind::UnknownArgument);
+ /// ```
+ /// What's happening is `-o` is getting `val1`, and because delimiters are required yet none
+ /// were present, it stops parsing `-o`. At this point it reaches `val2` and because no
+ /// positional arguments have been defined, it's an error of an unexpected argument.
+ ///
+ /// In this final example, we contrast the above with `clap`'s default behavior where the above
+ /// is *not* an error.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let delims = App::new("prog")
+ /// .arg(Arg::with_name("opt")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .multiple(true))
+ /// .get_matches_from(vec![
+ /// "prog", "-o", "val1", "val2", "val3",
+ /// ]);
+ ///
+ /// assert!(delims.is_present("opt"));
+ /// assert_eq!(delims.values_of("opt").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+ /// ```
+ /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter
+ pub fn require_delimiter(mut self, d: bool) -> Self {
+ if d {
+ self = self.use_delimiter(true);
+ self.unsetb(ArgSettings::ValueDelimiterNotSet);
+ self.setb(ArgSettings::UseValueDelimiter);
+ self.set(ArgSettings::RequireDelimiter)
+ } else {
+ self = self.use_delimiter(false);
+ self.unsetb(ArgSettings::UseValueDelimiter);
+ self.unset(ArgSettings::RequireDelimiter)
+ }
+ }
+
+ /// Specifies the separator to use when values are clumped together, defaults to `,` (comma).
+ ///
+ /// **NOTE:** implicitly sets [`Arg::use_delimiter(true)`]
+ ///
+ /// **NOTE:** implicitly sets [`Arg::takes_value(true)`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("config")
+ /// .short("c")
+ /// .long("config")
+ /// .value_delimiter(";"))
+ /// .get_matches_from(vec![
+ /// "prog", "--config=val1;val2;val3"
+ /// ]);
+ ///
+ /// assert_eq!(m.values_of("config").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"])
+ /// ```
+ /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ pub fn value_delimiter(mut self, d: &str) -> Self {
+ self.unsetb(ArgSettings::ValueDelimiterNotSet);
+ self.setb(ArgSettings::TakesValue);
+ self.setb(ArgSettings::UseValueDelimiter);
+ self.v.val_delim = Some(
+ d.chars()
+ .nth(0)
+ .expect("Failed to get value_delimiter from arg"),
+ );
+ self
+ }
+
+ /// Specify multiple names for values of option arguments. These names are cosmetic only, used
+ /// for help and usage strings only. The names are **not** used to access arguments. The values
+ /// of the arguments are accessed in numeric order (i.e. if you specify two names `one` and
+ /// `two` `one` will be the first matched value, `two` will be the second).
+ ///
+ /// This setting can be very helpful when describing the type of input the user should be
+ /// using, such as `FILE`, `INTERFACE`, etc. Although not required, it's somewhat convention to
+ /// use all capital letters for the value name.
+ ///
+ /// **Pro Tip:** It may help to use [`Arg::next_line_help(true)`] if there are long, or
+ /// multiple value names in order to not throw off the help text alignment of all options.
+ ///
+ /// **NOTE:** This implicitly sets [`Arg::number_of_values`] if the number of value names is
+ /// greater than one. I.e. be aware that the number of "names" you set for the values, will be
+ /// the *exact* number of values required to satisfy this argument
+ ///
+ /// **NOTE:** implicitly sets [`Arg::takes_value(true)`]
+ ///
+ /// **NOTE:** Does *not* require or imply [`Arg::multiple(true)`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("speed")
+ /// .short("s")
+ /// .value_names(&["fast", "slow"])
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("io")
+ /// .long("io-files")
+ /// .value_names(&["INFILE", "OUTFILE"]))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ /// Running the above program produces the following output
+ ///
+ /// ```notrust
+ /// valnames
+ ///
+ /// USAGE:
+ /// valnames [FLAGS] [OPTIONS]
+ ///
+ /// FLAGS:
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ ///
+ /// OPTIONS:
+ /// --io-files <INFILE> <OUTFILE> Some help text
+ /// ```
+ /// [`Arg::next_line_help(true)`]: ./struct.Arg.html#method.next_line_help
+ /// [`Arg::number_of_values`]: ./struct.Arg.html#method.number_of_values
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ pub fn value_names(mut self, names: &[&'b str]) -> Self {
+ self.setb(ArgSettings::TakesValue);
+ if self.is_set(ArgSettings::ValueDelimiterNotSet) {
+ self.unsetb(ArgSettings::ValueDelimiterNotSet);
+ self.setb(ArgSettings::UseValueDelimiter);
+ }
+ if let Some(ref mut vals) = self.v.val_names {
+ let mut l = vals.len();
+ for s in names {
+ vals.insert(l, s);
+ l += 1;
+ }
+ } else {
+ let mut vm = VecMap::new();
+ for (i, n) in names.iter().enumerate() {
+ vm.insert(i, *n);
+ }
+ self.v.val_names = Some(vm);
+ }
+ self
+ }
+
+ /// Specifies the name for value of [option] or [positional] arguments inside of help
+ /// documentation. This name is cosmetic only, the name is **not** used to access arguments.
+ /// This setting can be very helpful when describing the type of input the user should be
+ /// using, such as `FILE`, `INTERFACE`, etc. Although not required, it's somewhat convention to
+ /// use all capital letters for the value name.
+ ///
+ /// **NOTE:** implicitly sets [`Arg::takes_value(true)`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("cfg")
+ /// .long("config")
+ /// .value_name("FILE")
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("config")
+ /// .long("config")
+ /// .value_name("FILE"))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ /// Running the above program produces the following output
+ ///
+ /// ```notrust
+ /// valnames
+ ///
+ /// USAGE:
+ /// valnames [FLAGS] [OPTIONS]
+ ///
+ /// FLAGS:
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ ///
+ /// OPTIONS:
+ /// --config <FILE> Some help text
+ /// ```
+ /// [option]: ./struct.Arg.html#method.takes_value
+ /// [positional]: ./struct.Arg.html#method.index
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ pub fn value_name(mut self, name: &'b str) -> Self {
+ self.setb(ArgSettings::TakesValue);
+ if let Some(ref mut vals) = self.v.val_names {
+ let l = vals.len();
+ vals.insert(l, name);
+ } else {
+ let mut vm = VecMap::new();
+ vm.insert(0, name);
+ self.v.val_names = Some(vm);
+ }
+ self
+ }
+
+ /// Specifies the value of the argument when *not* specified at runtime.
+ ///
+ /// **NOTE:** If the user *does not* use this argument at runtime, [`ArgMatches::occurrences_of`]
+ /// will return `0` even though the [`ArgMatches::value_of`] will return the default specified.
+ ///
+ /// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will
+ /// still return `true`. If you wish to determine whether the argument was used at runtime or
+ /// not, consider [`ArgMatches::occurrences_of`] which will return `0` if the argument was *not*
+ /// used at runtime.
+ ///
+ /// **NOTE:** This setting is perfectly compatible with [`Arg::default_value_if`] but slightly
+ /// different. `Arg::default_value` *only* takes affect when the user has not provided this arg
+ /// at runtime. `Arg::default_value_if` however only takes affect when the user has not provided
+ /// a value at runtime **and** these other conditions are met as well. If you have set
+ /// `Arg::default_value` and `Arg::default_value_if`, and the user **did not** provide a this
+ /// arg at runtime, nor did were the conditions met for `Arg::default_value_if`, the
+ /// `Arg::default_value` will be applied.
+ ///
+ /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`].
+ ///
+ /// **NOTE:** This setting effectively disables `AppSettings::ArgRequiredElseHelp` if used in
+ /// conjunction as it ensures that some argument will always be present.
+ ///
+ /// # Examples
+ ///
+ /// First we use the default value without providing any value at runtime.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("opt")
+ /// .long("myopt")
+ /// .default_value("myval"))
+ /// .get_matches_from(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("opt"), Some("myval"));
+ /// assert!(m.is_present("opt"));
+ /// assert_eq!(m.occurrences_of("opt"), 0);
+ /// ```
+ ///
+ /// Next we provide a value at runtime to override the default.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("opt")
+ /// .long("myopt")
+ /// .default_value("myval"))
+ /// .get_matches_from(vec![
+ /// "prog", "--myopt=non_default"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("opt"), Some("non_default"));
+ /// assert!(m.is_present("opt"));
+ /// assert_eq!(m.occurrences_of("opt"), 1);
+ /// ```
+ /// [`ArgMatches::occurrences_of`]: ./struct.ArgMatches.html#method.occurrences_of
+ /// [`ArgMatches::value_of`]: ./struct.ArgMatches.html#method.value_of
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ /// [`ArgMatches::is_present`]: ./struct.ArgMatches.html#method.is_present
+ /// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if
+ pub fn default_value(self, val: &'a str) -> Self {
+ self.default_value_os(OsStr::from_bytes(val.as_bytes()))
+ }
+
+ /// Provides a default value in the exact same manner as [`Arg::default_value`]
+ /// only using [`OsStr`]s instead.
+ /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
+ /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
+ pub fn default_value_os(mut self, val: &'a OsStr) -> Self {
+ self.setb(ArgSettings::TakesValue);
+ self.v.default_val = Some(val);
+ self
+ }
+
+ /// Specifies the value of the argument if `arg` has been used at runtime. If `val` is set to
+ /// `None`, `arg` only needs to be present. If `val` is set to `"some-val"` then `arg` must be
+ /// present at runtime **and** have the value `val`.
+ ///
+ /// **NOTE:** This setting is perfectly compatible with [`Arg::default_value`] but slightly
+ /// different. `Arg::default_value` *only* takes affect when the user has not provided this arg
+ /// at runtime. This setting however only takes affect when the user has not provided a value at
+ /// runtime **and** these other conditions are met as well. If you have set `Arg::default_value`
+ /// and `Arg::default_value_if`, and the user **did not** provide a this arg at runtime, nor did
+ /// were the conditions met for `Arg::default_value_if`, the `Arg::default_value` will be
+ /// applied.
+ ///
+ /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`].
+ ///
+ /// **NOTE:** If using YAML the values should be laid out as follows (`None` can be represented
+ /// as `null` in YAML)
+ ///
+ /// ```yaml
+ /// default_value_if:
+ /// - [arg, val, default]
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// First we use the default value only if another arg is present at runtime.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag"))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .default_value_if("flag", None, "default"))
+ /// .get_matches_from(vec![
+ /// "prog", "--flag"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("other"), Some("default"));
+ /// ```
+ ///
+ /// Next we run the same test, but without providing `--flag`.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag"))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .default_value_if("flag", None, "default"))
+ /// .get_matches_from(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("other"), None);
+ /// ```
+ ///
+ /// Now lets only use the default value if `--opt` contains the value `special`.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("opt")
+ /// .takes_value(true)
+ /// .long("opt"))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .default_value_if("opt", Some("special"), "default"))
+ /// .get_matches_from(vec![
+ /// "prog", "--opt", "special"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("other"), Some("default"));
+ /// ```
+ ///
+ /// We can run the same test and provide any value *other than* `special` and we won't get a
+ /// default value.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("opt")
+ /// .takes_value(true)
+ /// .long("opt"))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .default_value_if("opt", Some("special"), "default"))
+ /// .get_matches_from(vec![
+ /// "prog", "--opt", "hahaha"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("other"), None);
+ /// ```
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
+ pub fn default_value_if(self, arg: &'a str, val: Option<&'b str>, default: &'b str) -> Self {
+ self.default_value_if_os(
+ arg,
+ val.map(str::as_bytes).map(OsStr::from_bytes),
+ OsStr::from_bytes(default.as_bytes()),
+ )
+ }
+
+ /// Provides a conditional default value in the exact same manner as [`Arg::default_value_if`]
+ /// only using [`OsStr`]s instead.
+ /// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if
+ /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
+ pub fn default_value_if_os(
+ mut self,
+ arg: &'a str,
+ val: Option<&'b OsStr>,
+ default: &'b OsStr,
+ ) -> Self {
+ self.setb(ArgSettings::TakesValue);
+ if let Some(ref mut vm) = self.v.default_vals_ifs {
+ let l = vm.len();
+ vm.insert(l, (arg, val, default));
+ } else {
+ let mut vm = VecMap::new();
+ vm.insert(0, (arg, val, default));
+ self.v.default_vals_ifs = Some(vm);
+ }
+ self
+ }
+
+ /// Specifies multiple values and conditions in the same manner as [`Arg::default_value_if`].
+ /// The method takes a slice of tuples in the `(arg, Option<val>, default)` format.
+ ///
+ /// **NOTE**: The conditions are stored in order and evaluated in the same order. I.e. the first
+ /// if multiple conditions are true, the first one found will be applied and the ultimate value.
+ ///
+ /// **NOTE:** If using YAML the values should be laid out as follows
+ ///
+ /// ```yaml
+ /// default_value_if:
+ /// - [arg, val, default]
+ /// - [arg2, null, default2]
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// First we use the default value only if another arg is present at runtime.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag"))
+ /// .arg(Arg::with_name("opt")
+ /// .long("opt")
+ /// .takes_value(true))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .default_value_ifs(&[
+ /// ("flag", None, "default"),
+ /// ("opt", Some("channal"), "chan"),
+ /// ]))
+ /// .get_matches_from(vec![
+ /// "prog", "--opt", "channal"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("other"), Some("chan"));
+ /// ```
+ ///
+ /// Next we run the same test, but without providing `--flag`.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag"))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .default_value_ifs(&[
+ /// ("flag", None, "default"),
+ /// ("opt", Some("channal"), "chan"),
+ /// ]))
+ /// .get_matches_from(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("other"), None);
+ /// ```
+ ///
+ /// We can also see that these values are applied in order, and if more than one condition is
+ /// true, only the first evaluated "wins"
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag"))
+ /// .arg(Arg::with_name("opt")
+ /// .long("opt")
+ /// .takes_value(true))
+ /// .arg(Arg::with_name("other")
+ /// .long("other")
+ /// .default_value_ifs(&[
+ /// ("flag", None, "default"),
+ /// ("opt", Some("channal"), "chan"),
+ /// ]))
+ /// .get_matches_from(vec![
+ /// "prog", "--opt", "channal", "--flag"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("other"), Some("default"));
+ /// ```
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
+ pub fn default_value_ifs(mut self, ifs: &[(&'a str, Option<&'b str>, &'b str)]) -> Self {
+ for &(arg, val, default) in ifs {
+ self = self.default_value_if_os(
+ arg,
+ val.map(str::as_bytes).map(OsStr::from_bytes),
+ OsStr::from_bytes(default.as_bytes()),
+ );
+ }
+ self
+ }
+
+ /// Provides multiple conditional default values in the exact same manner as
+ /// [`Arg::default_value_ifs`] only using [`OsStr`]s instead.
+ /// [`Arg::default_value_ifs`]: ./struct.Arg.html#method.default_value_ifs
+ /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
+ #[cfg_attr(feature = "lints", allow(explicit_counter_loop))]
+ pub fn default_value_ifs_os(mut self, ifs: &[(&'a str, Option<&'b OsStr>, &'b OsStr)]) -> Self {
+ for &(arg, val, default) in ifs {
+ self = self.default_value_if_os(arg, val, default);
+ }
+ self
+ }
+
+ /// Specifies that if the value is not passed in as an argument, that it should be retrieved
+ /// from the environment, if available. If it is not present in the environment, then default
+ /// rules will apply.
+ ///
+ /// **NOTE:** If the user *does not* use this argument at runtime, [`ArgMatches::occurrences_of`]
+ /// will return `0` even though the [`ArgMatches::value_of`] will return the default specified.
+ ///
+ /// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will
+ /// return `true` if the variable is present in the environment . If you wish to determine whether
+ /// the argument was used at runtime or not, consider [`ArgMatches::occurrences_of`] which will
+ /// return `0` if the argument was *not* used at runtime.
+ ///
+ /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`].
+ ///
+ /// **NOTE:** If [`Arg::multiple(true)`] is set then [`Arg::use_delimiter(true)`] should also be
+ /// set. Otherwise, only a single argument will be returned from the environment variable. The
+ /// default delimiter is `,` and follows all the other delimiter rules.
+ ///
+ /// # Examples
+ ///
+ /// In this example, we show the variable coming from the environment:
+ ///
+ /// ```rust
+ /// # use std::env;
+ /// # use clap::{App, Arg};
+ ///
+ /// env::set_var("MY_FLAG", "env");
+ ///
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag")
+ /// .env("MY_FLAG"))
+ /// .get_matches_from(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("flag"), Some("env"));
+ /// ```
+ ///
+ /// In this example, we show the variable coming from an option on the CLI:
+ ///
+ /// ```rust
+ /// # use std::env;
+ /// # use clap::{App, Arg};
+ ///
+ /// env::set_var("MY_FLAG", "env");
+ ///
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag")
+ /// .env("MY_FLAG"))
+ /// .get_matches_from(vec![
+ /// "prog", "--flag", "opt"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("flag"), Some("opt"));
+ /// ```
+ ///
+ /// In this example, we show the variable coming from the environment even with the
+ /// presence of a default:
+ ///
+ /// ```rust
+ /// # use std::env;
+ /// # use clap::{App, Arg};
+ ///
+ /// env::set_var("MY_FLAG", "env");
+ ///
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag")
+ /// .env("MY_FLAG")
+ /// .default_value("default"))
+ /// .get_matches_from(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert_eq!(m.value_of("flag"), Some("env"));
+ /// ```
+ ///
+ /// In this example, we show the use of multiple values in a single environment variable:
+ ///
+ /// ```rust
+ /// # use std::env;
+ /// # use clap::{App, Arg};
+ ///
+ /// env::set_var("MY_FLAG_MULTI", "env1,env2");
+ ///
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("flag")
+ /// .long("flag")
+ /// .env("MY_FLAG_MULTI")
+ /// .multiple(true)
+ /// .use_delimiter(true))
+ /// .get_matches_from(vec![
+ /// "prog"
+ /// ]);
+ ///
+ /// assert_eq!(m.values_of("flag").unwrap().collect::<Vec<_>>(), vec!["env1", "env2"]);
+ /// ```
+ /// [`ArgMatches::occurrences_of`]: ./struct.ArgMatches.html#method.occurrences_of
+ /// [`ArgMatches::value_of`]: ./struct.ArgMatches.html#method.value_of
+ /// [`ArgMatches::is_present`]: ./struct.ArgMatches.html#method.is_present
+ /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter
+ pub fn env(self, name: &'a str) -> Self {
+ self.env_os(OsStr::new(name))
+ }
+
+ /// Specifies that if the value is not passed in as an argument, that it should be retrieved
+ /// from the environment if available in the exact same manner as [`Arg::env`] only using
+ /// [`OsStr`]s instead.
+ pub fn env_os(mut self, name: &'a OsStr) -> Self {
+ self.setb(ArgSettings::TakesValue);
+
+ self.v.env = Some((name, env::var_os(name)));
+ self
+ }
+
+ /// @TODO @p2 @docs @release: write docs
+ pub fn hide_env_values(self, hide: bool) -> Self {
+ if hide {
+ self.set(ArgSettings::HideEnvValues)
+ } else {
+ self.unset(ArgSettings::HideEnvValues)
+ }
+ }
+
+ /// When set to `true` the help string will be displayed on the line after the argument and
+ /// indented once. This can be helpful for arguments with very long or complex help messages.
+ /// This can also be helpful for arguments with very long flag names, or many/long value names.
+ ///
+ /// **NOTE:** To apply this setting to all arguments consider using
+ /// [`AppSettings::NextLineHelp`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("opt")
+ /// .long("long-option-flag")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .value_names(&["value1", "value2"])
+ /// .help("Some really long help and complex\n\
+ /// help that makes more sense to be\n\
+ /// on a line after the option")
+ /// .next_line_help(true))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ ///
+ /// The above example displays the following help message
+ ///
+ /// ```notrust
+ /// nlh
+ ///
+ /// USAGE:
+ /// nlh [FLAGS] [OPTIONS]
+ ///
+ /// FLAGS:
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ ///
+ /// OPTIONS:
+ /// -o, --long-option-flag <value1> <value2>
+ /// Some really long help and complex
+ /// help that makes more sense to be
+ /// on a line after the option
+ /// ```
+ /// [`AppSettings::NextLineHelp`]: ./enum.AppSettings.html#variant.NextLineHelp
+ pub fn next_line_help(mut self, nlh: bool) -> Self {
+ if nlh {
+ self.setb(ArgSettings::NextLineHelp);
+ } else {
+ self.unsetb(ArgSettings::NextLineHelp);
+ }
+ self
+ }
+
+ /// Allows custom ordering of args within the help message. Args with a lower value will be
+ /// displayed first in the help message. This is helpful when one would like to emphasise
+ /// frequently used args, or prioritize those towards the top of the list. Duplicate values
+ /// **are** allowed. Args with duplicate display orders will be displayed in alphabetical
+ /// order.
+ ///
+ /// **NOTE:** The default is 999 for all arguments.
+ ///
+ /// **NOTE:** This setting is ignored for [positional arguments] which are always displayed in
+ /// [index] order.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("a") // Typically args are grouped alphabetically by name.
+ /// // Args without a display_order have a value of 999 and are
+ /// // displayed alphabetically with all other 999 valued args.
+ /// .long("long-option")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .help("Some help and text"))
+ /// .arg(Arg::with_name("b")
+ /// .long("other-option")
+ /// .short("O")
+ /// .takes_value(true)
+ /// .display_order(1) // In order to force this arg to appear *first*
+ /// // all we have to do is give it a value lower than 999.
+ /// // Any other args with a value of 1 will be displayed
+ /// // alphabetically with this one...then 2 values, then 3, etc.
+ /// .help("I should be first!"))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ ///
+ /// The above example displays the following help message
+ ///
+ /// ```notrust
+ /// cust-ord
+ ///
+ /// USAGE:
+ /// cust-ord [FLAGS] [OPTIONS]
+ ///
+ /// FLAGS:
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ ///
+ /// OPTIONS:
+ /// -O, --other-option <b> I should be first!
+ /// -o, --long-option <a> Some help and text
+ /// ```
+ /// [positional arguments]: ./struct.Arg.html#method.index
+ /// [index]: ./struct.Arg.html#method.index
+ pub fn display_order(mut self, ord: usize) -> Self {
+ self.s.disp_ord = ord;
+ self
+ }
+
+ /// Indicates that all parameters passed after this should not be parsed
+ /// individually, but rather passed in their entirety. It is worth noting
+ /// that setting this requires all values to come after a `--` to indicate they
+ /// should all be captured. For example:
+ ///
+ /// ```notrust
+ /// --foo something -- -v -v -v -b -b -b --baz -q -u -x
+ /// ```
+ /// Will result in everything after `--` to be considered one raw argument. This behavior
+ /// may not be exactly what you are expecting and using [`AppSettings::TrailingVarArg`]
+ /// may be more appropriate.
+ ///
+ /// **NOTE:** Implicitly sets [`Arg::multiple(true)`], [`Arg::allow_hyphen_values(true)`], and
+ /// [`Arg::last(true)`] when set to `true`
+ ///
+ /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+ /// [`Arg::allow_hyphen_values(true)`]: ./struct.Arg.html#method.allow_hyphen_values
+ /// [`Arg::last(true)`]: ./struct.Arg.html#method.last
+ /// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg
+ pub fn raw(self, raw: bool) -> Self {
+ self.multiple(raw).allow_hyphen_values(raw).last(raw)
+ }
+
+ /// Hides an argument from short help message output.
+ ///
+ /// **NOTE:** This does **not** hide the argument from usage strings on error
+ ///
+ /// **NOTE:** Setting this option will cause next-line-help output style to be used
+ /// when long help (`--help`) is called.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("debug")
+ /// .hidden_short_help(true)
+ /// # ;
+ /// ```
+ /// Setting `hidden_short_help(true)` will hide the argument when displaying short help text
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config")
+ /// .hidden_short_help(true)
+ /// .help("Some help text describing the --config arg"))
+ /// .get_matches_from(vec![
+ /// "prog", "-h"
+ /// ]);
+ /// ```
+ ///
+ /// The above example displays
+ ///
+ /// ```notrust
+ /// helptest
+ ///
+ /// USAGE:
+ /// helptest [FLAGS]
+ ///
+ /// FLAGS:
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ /// ```
+ ///
+ /// However, when --help is called
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config")
+ /// .hidden_short_help(true)
+ /// .help("Some help text describing the --config arg"))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ ///
+ /// Then the following would be displayed
+ ///
+ /// ```notrust
+ /// helptest
+ ///
+ /// USAGE:
+ /// helptest [FLAGS]
+ ///
+ /// FLAGS:
+ /// --config Some help text describing the --config arg
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ /// ```
+ pub fn hidden_short_help(self, hide: bool) -> Self {
+ if hide {
+ self.set(ArgSettings::HiddenShortHelp)
+ } else {
+ self.unset(ArgSettings::HiddenShortHelp)
+ }
+ }
+
+ /// Hides an argument from long help message output.
+ ///
+ /// **NOTE:** This does **not** hide the argument from usage strings on error
+ ///
+ /// **NOTE:** Setting this option will cause next-line-help output style to be used
+ /// when long help (`--help`) is called.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// Arg::with_name("debug")
+ /// .hidden_long_help(true)
+ /// # ;
+ /// ```
+ /// Setting `hidden_long_help(true)` will hide the argument when displaying long help text
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config")
+ /// .hidden_long_help(true)
+ /// .help("Some help text describing the --config arg"))
+ /// .get_matches_from(vec![
+ /// "prog", "--help"
+ /// ]);
+ /// ```
+ ///
+ /// The above example displays
+ ///
+ /// ```notrust
+ /// helptest
+ ///
+ /// USAGE:
+ /// helptest [FLAGS]
+ ///
+ /// FLAGS:
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ /// ```
+ ///
+ /// However, when -h is called
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("prog")
+ /// .arg(Arg::with_name("cfg")
+ /// .long("config")
+ /// .hidden_long_help(true)
+ /// .help("Some help text describing the --config arg"))
+ /// .get_matches_from(vec![
+ /// "prog", "-h"
+ /// ]);
+ /// ```
+ ///
+ /// Then the following would be displayed
+ ///
+ /// ```notrust
+ /// helptest
+ ///
+ /// USAGE:
+ /// helptest [FLAGS]
+ ///
+ /// FLAGS:
+ /// --config Some help text describing the --config arg
+ /// -h, --help Prints help information
+ /// -V, --version Prints version information
+ /// ```
+ pub fn hidden_long_help(self, hide: bool) -> Self {
+ if hide {
+ self.set(ArgSettings::HiddenLongHelp)
+ } else {
+ self.unset(ArgSettings::HiddenLongHelp)
+ }
+ }
+
+ /// Checks if one of the [`ArgSettings`] settings is set for the argument.
+ ///
+ /// [`ArgSettings`]: ./enum.ArgSettings.html
+ pub fn is_set(&self, s: ArgSettings) -> bool {
+ self.b.is_set(s)
+ }
+
+ /// Sets one of the [`ArgSettings`] settings for the argument.
+ ///
+ /// [`ArgSettings`]: ./enum.ArgSettings.html
+ pub fn set(mut self, s: ArgSettings) -> Self {
+ self.setb(s);
+ self
+ }
+
+ /// Unsets one of the [`ArgSettings`] settings for the argument.
+ ///
+ /// [`ArgSettings`]: ./enum.ArgSettings.html
+ pub fn unset(mut self, s: ArgSettings) -> Self {
+ self.unsetb(s);
+ self
+ }
+
+ #[doc(hidden)]
+ pub fn setb(&mut self, s: ArgSettings) {
+ self.b.set(s);
+ }
+
+ #[doc(hidden)]
+ pub fn unsetb(&mut self, s: ArgSettings) {
+ self.b.unset(s);
+ }
+}
+
+impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> {
+ fn from(a: &'z Arg<'a, 'b>) -> Self {
+ Arg {
+ b: a.b.clone(),
+ v: a.v.clone(),
+ s: a.s.clone(),
+ index: a.index,
+ r_ifs: a.r_ifs.clone(),
+ }
+ }
+}
+
+impl<'n, 'e> PartialEq for Arg<'n, 'e> {
+ fn eq(&self, other: &Arg<'n, 'e>) -> bool {
+ self.b == other.b
+ }
+}
diff --git a/clap/src/args/arg_builder/base.rs b/clap/src/args/arg_builder/base.rs
new file mode 100644
index 0000000..fef9d8a
--- /dev/null
+++ b/clap/src/args/arg_builder/base.rs
@@ -0,0 +1,38 @@
+use args::{Arg, ArgFlags, ArgSettings};
+
+#[derive(Debug, Clone, Default)]
+pub struct Base<'a, 'b>
+where
+ 'a: 'b,
+{
+ pub name: &'a str,
+ pub help: Option<&'b str>,
+ pub long_help: Option<&'b str>,
+ pub blacklist: Option<Vec<&'a str>>,
+ pub settings: ArgFlags,
+ pub r_unless: Option<Vec<&'a str>>,
+ pub overrides: Option<Vec<&'a str>>,
+ pub groups: Option<Vec<&'a str>>,
+ pub requires: Option<Vec<(Option<&'b str>, &'a str)>>,
+}
+
+impl<'n, 'e> Base<'n, 'e> {
+ pub fn new(name: &'n str) -> Self {
+ Base {
+ name: name,
+ ..Default::default()
+ }
+ }
+
+ pub fn set(&mut self, s: ArgSettings) { self.settings.set(s); }
+ pub fn unset(&mut self, s: ArgSettings) { self.settings.unset(s); }
+ pub fn is_set(&self, s: ArgSettings) -> bool { self.settings.is_set(s) }
+}
+
+impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Base<'n, 'e> {
+ fn from(a: &'z Arg<'n, 'e>) -> Self { a.b.clone() }
+}
+
+impl<'n, 'e> PartialEq for Base<'n, 'e> {
+ fn eq(&self, other: &Base<'n, 'e>) -> bool { self.name == other.name }
+}
diff --git a/clap/src/args/arg_builder/flag.rs b/clap/src/args/arg_builder/flag.rs
new file mode 100644
index 0000000..641e777
--- /dev/null
+++ b/clap/src/args/arg_builder/flag.rs
@@ -0,0 +1,159 @@
+// Std
+use std::convert::From;
+use std::fmt::{Display, Formatter, Result};
+use std::rc::Rc;
+use std::result::Result as StdResult;
+use std::ffi::{OsStr, OsString};
+use std::mem;
+
+// Internal
+use Arg;
+use args::{AnyArg, ArgSettings, Base, DispOrder, Switched};
+use map::{self, VecMap};
+
+#[derive(Default, Clone, Debug)]
+#[doc(hidden)]
+pub struct FlagBuilder<'n, 'e>
+where
+ 'n: 'e,
+{
+ pub b: Base<'n, 'e>,
+ pub s: Switched<'e>,
+}
+
+impl<'n, 'e> FlagBuilder<'n, 'e> {
+ pub fn new(name: &'n str) -> Self {
+ FlagBuilder {
+ b: Base::new(name),
+ ..Default::default()
+ }
+ }
+}
+
+impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
+ fn from(a: &'z Arg<'a, 'b>) -> Self {
+ FlagBuilder {
+ b: Base::from(a),
+ s: Switched::from(a),
+ }
+ }
+}
+
+impl<'a, 'b> From<Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
+ fn from(mut a: Arg<'a, 'b>) -> Self {
+ FlagBuilder {
+ b: mem::replace(&mut a.b, Base::default()),
+ s: mem::replace(&mut a.s, Switched::default()),
+ }
+ }
+}
+
+impl<'n, 'e> Display for FlagBuilder<'n, 'e> {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ if let Some(l) = self.s.long {
+ write!(f, "--{}", l)?;
+ } else {
+ write!(f, "-{}", self.s.short.unwrap())?;
+ }
+
+ Ok(())
+ }
+}
+
+impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
+ fn name(&self) -> &'n str { self.b.name }
+ fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
+ fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
+ self.b.requires.as_ref().map(|o| &o[..])
+ }
+ fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
+ fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
+ fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
+ fn has_switch(&self) -> bool { true }
+ fn takes_value(&self) -> bool { false }
+ fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
+ fn max_vals(&self) -> Option<u64> { None }
+ fn val_names(&self) -> Option<&VecMap<&'e str>> { None }
+ fn num_vals(&self) -> Option<u64> { None }
+ fn possible_vals(&self) -> Option<&[&'e str]> { None }
+ fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> { None }
+ fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> { None }
+ fn min_vals(&self) -> Option<u64> { None }
+ fn short(&self) -> Option<char> { self.s.short }
+ fn long(&self) -> Option<&'e str> { self.s.long }
+ fn val_delim(&self) -> Option<char> { None }
+ fn help(&self) -> Option<&'e str> { self.b.help }
+ fn long_help(&self) -> Option<&'e str> { self.b.long_help }
+ fn val_terminator(&self) -> Option<&'e str> { None }
+ fn default_val(&self) -> Option<&'e OsStr> { None }
+ fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
+ None
+ }
+ fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { None }
+ fn longest_filter(&self) -> bool { self.s.long.is_some() }
+ fn aliases(&self) -> Option<Vec<&'e str>> {
+ if let Some(ref aliases) = self.s.aliases {
+ let vis_aliases: Vec<_> = aliases
+ .iter()
+ .filter_map(|&(n, v)| if v { Some(n) } else { None })
+ .collect();
+ if vis_aliases.is_empty() {
+ None
+ } else {
+ Some(vis_aliases)
+ }
+ } else {
+ None
+ }
+ }
+}
+
+impl<'n, 'e> DispOrder for FlagBuilder<'n, 'e> {
+ fn disp_ord(&self) -> usize { self.s.disp_ord }
+}
+
+impl<'n, 'e> PartialEq for FlagBuilder<'n, 'e> {
+ fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { self.b == other.b }
+}
+
+#[cfg(test)]
+mod test {
+ use args::settings::ArgSettings;
+ use super::FlagBuilder;
+
+ #[test]
+ fn flagbuilder_display() {
+ let mut f = FlagBuilder::new("flg");
+ f.b.settings.set(ArgSettings::Multiple);
+ f.s.long = Some("flag");
+
+ assert_eq!(&*format!("{}", f), "--flag");
+
+ let mut f2 = FlagBuilder::new("flg");
+ f2.s.short = Some('f');
+
+ assert_eq!(&*format!("{}", f2), "-f");
+ }
+
+ #[test]
+ fn flagbuilder_display_single_alias() {
+ let mut f = FlagBuilder::new("flg");
+ f.s.long = Some("flag");
+ f.s.aliases = Some(vec![("als", true)]);
+
+ assert_eq!(&*format!("{}", f), "--flag");
+ }
+
+ #[test]
+ fn flagbuilder_display_multiple_aliases() {
+ let mut f = FlagBuilder::new("flg");
+ f.s.short = Some('f');
+ f.s.aliases = Some(vec![
+ ("alias_not_visible", false),
+ ("f2", true),
+ ("f3", true),
+ ("f4", true),
+ ]);
+ assert_eq!(&*format!("{}", f), "-f");
+ }
+}
diff --git a/clap/src/args/arg_builder/mod.rs b/clap/src/args/arg_builder/mod.rs
new file mode 100644
index 0000000..d1a7a66
--- /dev/null
+++ b/clap/src/args/arg_builder/mod.rs
@@ -0,0 +1,13 @@
+pub use self::flag::FlagBuilder;
+pub use self::option::OptBuilder;
+pub use self::positional::PosBuilder;
+pub use self::base::Base;
+pub use self::switched::Switched;
+pub use self::valued::Valued;
+
+mod flag;
+mod positional;
+mod option;
+mod base;
+mod valued;
+mod switched;
diff --git a/clap/src/args/arg_builder/option.rs b/clap/src/args/arg_builder/option.rs
new file mode 100644
index 0000000..4bb147a
--- /dev/null
+++ b/clap/src/args/arg_builder/option.rs
@@ -0,0 +1,244 @@
+// Std
+use std::fmt::{Display, Formatter, Result};
+use std::rc::Rc;
+use std::result::Result as StdResult;
+use std::ffi::{OsStr, OsString};
+use std::mem;
+
+// Internal
+use args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched, Valued};
+use map::{self, VecMap};
+use INTERNAL_ERROR_MSG;
+
+#[allow(missing_debug_implementations)]
+#[doc(hidden)]
+#[derive(Default, Clone)]
+pub struct OptBuilder<'n, 'e>
+where
+ 'n: 'e,
+{
+ pub b: Base<'n, 'e>,
+ pub s: Switched<'e>,
+ pub v: Valued<'n, 'e>,
+}
+
+impl<'n, 'e> OptBuilder<'n, 'e> {
+ pub fn new(name: &'n str) -> Self {
+ OptBuilder {
+ b: Base::new(name),
+ ..Default::default()
+ }
+ }
+}
+
+impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> {
+ fn from(a: &'z Arg<'n, 'e>) -> Self {
+ OptBuilder {
+ b: Base::from(a),
+ s: Switched::from(a),
+ v: Valued::from(a),
+ }
+ }
+}
+
+impl<'n, 'e> From<Arg<'n, 'e>> for OptBuilder<'n, 'e> {
+ fn from(mut a: Arg<'n, 'e>) -> Self {
+ a.v.fill_in();
+ OptBuilder {
+ b: mem::replace(&mut a.b, Base::default()),
+ s: mem::replace(&mut a.s, Switched::default()),
+ v: mem::replace(&mut a.v, Valued::default()),
+ }
+ }
+}
+
+impl<'n, 'e> Display for OptBuilder<'n, 'e> {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ debugln!("OptBuilder::fmt:{}", self.b.name);
+ let sep = if self.b.is_set(ArgSettings::RequireEquals) {
+ "="
+ } else {
+ " "
+ };
+ // Write the name such --long or -l
+ if let Some(l) = self.s.long {
+ write!(f, "--{}{}", l, sep)?;
+ } else {
+ write!(f, "-{}{}", self.s.short.unwrap(), sep)?;
+ }
+ let delim = if self.is_set(ArgSettings::RequireDelimiter) {
+ self.v.val_delim.expect(INTERNAL_ERROR_MSG)
+ } else {
+ ' '
+ };
+
+ // Write the values such as <name1> <name2>
+ if let Some(ref vec) = self.v.val_names {
+ let mut it = vec.iter().peekable();
+ while let Some((_, val)) = it.next() {
+ write!(f, "<{}>", val)?;
+ if it.peek().is_some() {
+ write!(f, "{}", delim)?;
+ }
+ }
+ let num = vec.len();
+ if self.is_set(ArgSettings::Multiple) && num == 1 {
+ write!(f, "...")?;
+ }
+ } else if let Some(num) = self.v.num_vals {
+ let mut it = (0..num).peekable();
+ while let Some(_) = it.next() {
+ write!(f, "<{}>", self.b.name)?;
+ if it.peek().is_some() {
+ write!(f, "{}", delim)?;
+ }
+ }
+ if self.is_set(ArgSettings::Multiple) && num == 1 {
+ write!(f, "...")?;
+ }
+ } else {
+ write!(
+ f,
+ "<{}>{}",
+ self.b.name,
+ if self.is_set(ArgSettings::Multiple) {
+ "..."
+ } else {
+ ""
+ }
+ )?;
+ }
+
+ Ok(())
+ }
+}
+
+impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
+ fn name(&self) -> &'n str { self.b.name }
+ fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
+ fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
+ self.b.requires.as_ref().map(|o| &o[..])
+ }
+ fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
+ fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
+ fn val_names(&self) -> Option<&VecMap<&'e str>> { self.v.val_names.as_ref() }
+ fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
+ fn has_switch(&self) -> bool { true }
+ fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
+ fn max_vals(&self) -> Option<u64> { self.v.max_vals }
+ fn val_terminator(&self) -> Option<&'e str> { self.v.terminator }
+ fn num_vals(&self) -> Option<u64> { self.v.num_vals }
+ fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) }
+ fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
+ self.v.validator.as_ref()
+ }
+ fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> {
+ self.v.validator_os.as_ref()
+ }
+ fn min_vals(&self) -> Option<u64> { self.v.min_vals }
+ fn short(&self) -> Option<char> { self.s.short }
+ fn long(&self) -> Option<&'e str> { self.s.long }
+ fn val_delim(&self) -> Option<char> { self.v.val_delim }
+ fn takes_value(&self) -> bool { true }
+ fn help(&self) -> Option<&'e str> { self.b.help }
+ fn long_help(&self) -> Option<&'e str> { self.b.long_help }
+ fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
+ fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
+ self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
+ }
+ fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> {
+ self.v
+ .env
+ .as_ref()
+ .map(|&(key, ref value)| (key, value.as_ref()))
+ }
+ fn longest_filter(&self) -> bool { true }
+ fn aliases(&self) -> Option<Vec<&'e str>> {
+ if let Some(ref aliases) = self.s.aliases {
+ let vis_aliases: Vec<_> = aliases
+ .iter()
+ .filter_map(|&(n, v)| if v { Some(n) } else { None })
+ .collect();
+ if vis_aliases.is_empty() {
+ None
+ } else {
+ Some(vis_aliases)
+ }
+ } else {
+ None
+ }
+ }
+}
+
+impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> {
+ fn disp_ord(&self) -> usize { self.s.disp_ord }
+}
+
+impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> {
+ fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool { self.b == other.b }
+}
+
+#[cfg(test)]
+mod test {
+ use args::settings::ArgSettings;
+ use super::OptBuilder;
+ use map::VecMap;
+
+ #[test]
+ fn optbuilder_display1() {
+ let mut o = OptBuilder::new("opt");
+ o.s.long = Some("option");
+ o.b.settings.set(ArgSettings::Multiple);
+
+ assert_eq!(&*format!("{}", o), "--option <opt>...");
+ }
+
+ #[test]
+ fn optbuilder_display2() {
+ let mut v_names = VecMap::new();
+ v_names.insert(0, "file");
+ v_names.insert(1, "name");
+
+ let mut o2 = OptBuilder::new("opt");
+ o2.s.short = Some('o');
+ o2.v.val_names = Some(v_names);
+
+ assert_eq!(&*format!("{}", o2), "-o <file> <name>");
+ }
+
+ #[test]
+ fn optbuilder_display3() {
+ let mut v_names = VecMap::new();
+ v_names.insert(0, "file");
+ v_names.insert(1, "name");
+
+ let mut o2 = OptBuilder::new("opt");
+ o2.s.short = Some('o');
+ o2.v.val_names = Some(v_names);
+ o2.b.settings.set(ArgSettings::Multiple);
+
+ assert_eq!(&*format!("{}", o2), "-o <file> <name>");
+ }
+
+ #[test]
+ fn optbuilder_display_single_alias() {
+ let mut o = OptBuilder::new("opt");
+ o.s.long = Some("option");
+ o.s.aliases = Some(vec![("als", true)]);
+
+ assert_eq!(&*format!("{}", o), "--option <opt>");
+ }
+
+ #[test]
+ fn optbuilder_display_multiple_aliases() {
+ let mut o = OptBuilder::new("opt");
+ o.s.long = Some("option");
+ o.s.aliases = Some(vec![
+ ("als_not_visible", false),
+ ("als2", true),
+ ("als3", true),
+ ("als4", true),
+ ]);
+ assert_eq!(&*format!("{}", o), "--option <opt>");
+ }
+}
diff --git a/clap/src/args/arg_builder/positional.rs b/clap/src/args/arg_builder/positional.rs
new file mode 100644
index 0000000..43fdca4
--- /dev/null
+++ b/clap/src/args/arg_builder/positional.rs
@@ -0,0 +1,229 @@
+// Std
+use std::borrow::Cow;
+use std::fmt::{Display, Formatter, Result};
+use std::rc::Rc;
+use std::result::Result as StdResult;
+use std::ffi::{OsStr, OsString};
+use std::mem;
+
+// Internal
+use Arg;
+use args::{AnyArg, ArgSettings, Base, DispOrder, Valued};
+use INTERNAL_ERROR_MSG;
+use map::{self, VecMap};
+
+#[allow(missing_debug_implementations)]
+#[doc(hidden)]
+#[derive(Clone, Default)]
+pub struct PosBuilder<'n, 'e>
+where
+ 'n: 'e,
+{
+ pub b: Base<'n, 'e>,
+ pub v: Valued<'n, 'e>,
+ pub index: u64,
+}
+
+impl<'n, 'e> PosBuilder<'n, 'e> {
+ pub fn new(name: &'n str, idx: u64) -> Self {
+ PosBuilder {
+ b: Base::new(name),
+ index: idx,
+ ..Default::default()
+ }
+ }
+
+ pub fn from_arg_ref(a: &Arg<'n, 'e>, idx: u64) -> Self {
+ let mut pb = PosBuilder {
+ b: Base::from(a),
+ v: Valued::from(a),
+ index: idx,
+ };
+ if a.v.max_vals.is_some() || a.v.min_vals.is_some()
+ || (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1)
+ {
+ pb.b.settings.set(ArgSettings::Multiple);
+ }
+ pb
+ }
+
+ pub fn from_arg(mut a: Arg<'n, 'e>, idx: u64) -> Self {
+ if a.v.max_vals.is_some() || a.v.min_vals.is_some()
+ || (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1)
+ {
+ a.b.settings.set(ArgSettings::Multiple);
+ }
+ PosBuilder {
+ b: mem::replace(&mut a.b, Base::default()),
+ v: mem::replace(&mut a.v, Valued::default()),
+ index: idx,
+ }
+ }
+
+ pub fn multiple_str(&self) -> &str {
+ let mult_vals = self.v
+ .val_names
+ .as_ref()
+ .map_or(true, |names| names.len() < 2);
+ if self.is_set(ArgSettings::Multiple) && mult_vals {
+ "..."
+ } else {
+ ""
+ }
+ }
+
+ pub fn name_no_brackets(&self) -> Cow<str> {
+ debugln!("PosBuilder::name_no_brackets;");
+ let mut delim = String::new();
+ delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
+ self.v.val_delim.expect(INTERNAL_ERROR_MSG)
+ } else {
+ ' '
+ });
+ if let Some(ref names) = self.v.val_names {
+ debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names);
+ if names.len() > 1 {
+ Cow::Owned(
+ names
+ .values()
+ .map(|n| format!("<{}>", n))
+ .collect::<Vec<_>>()
+ .join(&*delim),
+ )
+ } else {
+ Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG))
+ }
+ } else {
+ debugln!("PosBuilder:name_no_brackets: just name");
+ Cow::Borrowed(self.b.name)
+ }
+ }
+}
+
+impl<'n, 'e> Display for PosBuilder<'n, 'e> {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ let mut delim = String::new();
+ delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
+ self.v.val_delim.expect(INTERNAL_ERROR_MSG)
+ } else {
+ ' '
+ });
+ if let Some(ref names) = self.v.val_names {
+ write!(
+ f,
+ "{}",
+ names
+ .values()
+ .map(|n| format!("<{}>", n))
+ .collect::<Vec<_>>()
+ .join(&*delim)
+ )?;
+ } else {
+ write!(f, "<{}>", self.b.name)?;
+ }
+ if self.b.settings.is_set(ArgSettings::Multiple)
+ && (self.v.val_names.is_none() || self.v.val_names.as_ref().unwrap().len() == 1)
+ {
+ write!(f, "...")?;
+ }
+
+ Ok(())
+ }
+}
+
+impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
+ fn name(&self) -> &'n str { self.b.name }
+ fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
+ fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
+ self.b.requires.as_ref().map(|o| &o[..])
+ }
+ fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
+ fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
+ fn val_names(&self) -> Option<&VecMap<&'e str>> { self.v.val_names.as_ref() }
+ fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
+ fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
+ fn has_switch(&self) -> bool { false }
+ fn max_vals(&self) -> Option<u64> { self.v.max_vals }
+ fn val_terminator(&self) -> Option<&'e str> { self.v.terminator }
+ fn num_vals(&self) -> Option<u64> { self.v.num_vals }
+ fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) }
+ fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
+ self.v.validator.as_ref()
+ }
+ fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> {
+ self.v.validator_os.as_ref()
+ }
+ fn min_vals(&self) -> Option<u64> { self.v.min_vals }
+ fn short(&self) -> Option<char> { None }
+ fn long(&self) -> Option<&'e str> { None }
+ fn val_delim(&self) -> Option<char> { self.v.val_delim }
+ fn takes_value(&self) -> bool { true }
+ fn help(&self) -> Option<&'e str> { self.b.help }
+ fn long_help(&self) -> Option<&'e str> { self.b.long_help }
+ fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
+ self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
+ }
+ fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
+ fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> {
+ self.v
+ .env
+ .as_ref()
+ .map(|&(key, ref value)| (key, value.as_ref()))
+ }
+ fn longest_filter(&self) -> bool { true }
+ fn aliases(&self) -> Option<Vec<&'e str>> { None }
+}
+
+impl<'n, 'e> DispOrder for PosBuilder<'n, 'e> {
+ fn disp_ord(&self) -> usize { self.index as usize }
+}
+
+impl<'n, 'e> PartialEq for PosBuilder<'n, 'e> {
+ fn eq(&self, other: &PosBuilder<'n, 'e>) -> bool { self.b == other.b }
+}
+
+#[cfg(test)]
+mod test {
+ use args::settings::ArgSettings;
+ use super::PosBuilder;
+ use map::VecMap;
+
+ #[test]
+ fn display_mult() {
+ let mut p = PosBuilder::new("pos", 1);
+ p.b.settings.set(ArgSettings::Multiple);
+
+ assert_eq!(&*format!("{}", p), "<pos>...");
+ }
+
+ #[test]
+ fn display_required() {
+ let mut p2 = PosBuilder::new("pos", 1);
+ p2.b.settings.set(ArgSettings::Required);
+
+ assert_eq!(&*format!("{}", p2), "<pos>");
+ }
+
+ #[test]
+ fn display_val_names() {
+ let mut p2 = PosBuilder::new("pos", 1);
+ let mut vm = VecMap::new();
+ vm.insert(0, "file1");
+ vm.insert(1, "file2");
+ p2.v.val_names = Some(vm);
+
+ assert_eq!(&*format!("{}", p2), "<file1> <file2>");
+ }
+
+ #[test]
+ fn display_val_names_req() {
+ let mut p2 = PosBuilder::new("pos", 1);
+ p2.b.settings.set(ArgSettings::Required);
+ let mut vm = VecMap::new();
+ vm.insert(0, "file1");
+ vm.insert(1, "file2");
+ p2.v.val_names = Some(vm);
+
+ assert_eq!(&*format!("{}", p2), "<file1> <file2>");
+ }
+}
diff --git a/clap/src/args/arg_builder/switched.rs b/clap/src/args/arg_builder/switched.rs
new file mode 100644
index 0000000..224b2f2
--- /dev/null
+++ b/clap/src/args/arg_builder/switched.rs
@@ -0,0 +1,38 @@
+use Arg;
+
+#[derive(Debug)]
+pub struct Switched<'b> {
+ pub short: Option<char>,
+ pub long: Option<&'b str>,
+ pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
+ pub disp_ord: usize,
+ pub unified_ord: usize,
+}
+
+impl<'e> Default for Switched<'e> {
+ fn default() -> Self {
+ Switched {
+ short: None,
+ long: None,
+ aliases: None,
+ disp_ord: 999,
+ unified_ord: 999,
+ }
+ }
+}
+
+impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Switched<'e> {
+ fn from(a: &'z Arg<'n, 'e>) -> Self { a.s.clone() }
+}
+
+impl<'e> Clone for Switched<'e> {
+ fn clone(&self) -> Self {
+ Switched {
+ short: self.short,
+ long: self.long,
+ aliases: self.aliases.clone(),
+ disp_ord: self.disp_ord,
+ unified_ord: self.unified_ord,
+ }
+ }
+}
diff --git a/clap/src/args/arg_builder/valued.rs b/clap/src/args/arg_builder/valued.rs
new file mode 100644
index 0000000..d70854d
--- /dev/null
+++ b/clap/src/args/arg_builder/valued.rs
@@ -0,0 +1,67 @@
+use std::rc::Rc;
+use std::ffi::{OsStr, OsString};
+
+use map::VecMap;
+
+use Arg;
+
+#[allow(missing_debug_implementations)]
+#[derive(Clone)]
+pub struct Valued<'a, 'b>
+where
+ 'a: 'b,
+{
+ pub possible_vals: Option<Vec<&'b str>>,
+ pub val_names: Option<VecMap<&'b str>>,
+ pub num_vals: Option<u64>,
+ pub max_vals: Option<u64>,
+ pub min_vals: Option<u64>,
+ pub validator: Option<Rc<Fn(String) -> Result<(), String>>>,
+ pub validator_os: Option<Rc<Fn(&OsStr) -> Result<(), OsString>>>,
+ pub val_delim: Option<char>,
+ pub default_val: Option<&'b OsStr>,
+ pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b OsStr>, &'b OsStr)>>,
+ pub env: Option<(&'a OsStr, Option<OsString>)>,
+ pub terminator: Option<&'b str>,
+}
+
+impl<'n, 'e> Default for Valued<'n, 'e> {
+ fn default() -> Self {
+ Valued {
+ possible_vals: None,
+ num_vals: None,
+ min_vals: None,
+ max_vals: None,
+ val_names: None,
+ validator: None,
+ validator_os: None,
+ val_delim: None,
+ default_val: None,
+ default_vals_ifs: None,
+ env: None,
+ terminator: None,
+ }
+ }
+}
+
+impl<'n, 'e> Valued<'n, 'e> {
+ pub fn fill_in(&mut self) {
+ if let Some(ref vec) = self.val_names {
+ if vec.len() > 1 {
+ self.num_vals = Some(vec.len() as u64);
+ }
+ }
+ }
+}
+
+impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Valued<'n, 'e> {
+ fn from(a: &'z Arg<'n, 'e>) -> Self {
+ let mut v = a.v.clone();
+ if let Some(ref vec) = a.v.val_names {
+ if vec.len() > 1 {
+ v.num_vals = Some(vec.len() as u64);
+ }
+ }
+ v
+ }
+}
diff --git a/clap/src/args/arg_matcher.rs b/clap/src/args/arg_matcher.rs
new file mode 100644
index 0000000..e1d8067
--- /dev/null
+++ b/clap/src/args/arg_matcher.rs
@@ -0,0 +1,218 @@
+// Std
+use std::collections::hash_map::{Entry, Iter};
+use std::collections::HashMap;
+use std::ffi::OsStr;
+use std::ops::Deref;
+use std::mem;
+
+// Internal
+use args::{ArgMatches, MatchedArg, SubCommand};
+use args::AnyArg;
+use args::settings::ArgSettings;
+
+#[doc(hidden)]
+#[allow(missing_debug_implementations)]
+pub struct ArgMatcher<'a>(pub ArgMatches<'a>);
+
+impl<'a> Default for ArgMatcher<'a> {
+ fn default() -> Self { ArgMatcher(ArgMatches::default()) }
+}
+
+impl<'a> ArgMatcher<'a> {
+ pub fn new() -> Self { ArgMatcher::default() }
+
+ pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>, check_all: bool) {
+ debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name())));
+ if let Some(aa) = a {
+ let mut self_done = false;
+ if let Some(a_overrides) = aa.overrides() {
+ for overr in a_overrides {
+ debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr);
+ if overr == &aa.name() {
+ self_done = true;
+ self.handle_self_overrides(a);
+ } else if self.is_present(overr) {
+ debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing from matches;", overr);
+ self.remove(overr);
+ for i in (0 .. required.len()).rev() {
+ if &required[i] == overr {
+ debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing required;", overr);
+ required.swap_remove(i);
+ break;
+ }
+ }
+ overrides.push((overr, aa.name()));
+ } else {
+ overrides.push((overr, aa.name()));
+ }
+ }
+ }
+ if check_all && !self_done {
+ self.handle_self_overrides(a);
+ }
+ }
+ }
+
+ pub fn handle_self_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>) {
+ debugln!("ArgMatcher::handle_self_overrides:{:?};", a.map_or(None, |a| Some(a.name())));
+ if let Some(aa) = a {
+ if !aa.has_switch() || aa.is_set(ArgSettings::Multiple) {
+ // positional args can't override self or else we would never advance to the next
+
+ // Also flags with --multiple set are ignored otherwise we could never have more
+ // than one
+ return;
+ }
+ if let Some(ma) = self.get_mut(aa.name()) {
+ if ma.vals.len() > 1 {
+ // swap_remove(0) would be O(1) but does not preserve order, which
+ // we need
+ ma.vals.remove(0);
+ ma.occurs = 1;
+ } else if !aa.takes_value() && ma.occurs > 1 {
+ ma.occurs = 1;
+ }
+ }
+ }
+ }
+
+ pub fn is_present(&self, name: &str) -> bool {
+ self.0.is_present(name)
+ }
+
+ pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) {
+ debugln!( "ArgMatcher::get_global_values: global_arg_vec={:?}", global_arg_vec );
+ let mut vals_map = HashMap::new();
+ self.fill_in_global_values(global_arg_vec, &mut vals_map);
+ }
+
+ fn fill_in_global_values(
+ &mut self,
+ global_arg_vec: &[&'a str],
+ vals_map: &mut HashMap<&'a str, MatchedArg>,
+ ) {
+ for global_arg in global_arg_vec {
+ if let Some(ma) = self.get(global_arg) {
+ // We have to check if the parent's global arg wasn't used but still exists
+ // such as from a default value.
+ //
+ // For example, `myprog subcommand --global-arg=value` where --global-arg defines
+ // a default value of `other` myprog would have an existing MatchedArg for
+ // --global-arg where the value is `other`, however the occurs will be 0.
+ let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
+ if parent_ma.occurs > 0 && ma.occurs == 0 {
+ parent_ma.clone()
+ } else {
+ ma.clone()
+ }
+ } else {
+ ma.clone()
+ };
+ vals_map.insert(global_arg, to_update);
+ }
+ }
+ if let Some(ref mut sc) = self.0.subcommand {
+ let mut am = ArgMatcher(mem::replace(&mut sc.matches, ArgMatches::new()));
+ am.fill_in_global_values(global_arg_vec, vals_map);
+ mem::swap(&mut am.0, &mut sc.matches);
+ }
+
+ for (name, matched_arg) in vals_map.into_iter() {
+ self.0.args.insert(name, matched_arg.clone());
+ }
+ }
+
+ pub fn get_mut(&mut self, arg: &str) -> Option<&mut MatchedArg> { self.0.args.get_mut(arg) }
+
+ pub fn get(&self, arg: &str) -> Option<&MatchedArg> { self.0.args.get(arg) }
+
+ pub fn remove(&mut self, arg: &str) { self.0.args.remove(arg); }
+
+ pub fn remove_all(&mut self, args: &[&str]) {
+ for &arg in args {
+ self.0.args.remove(arg);
+ }
+ }
+
+ pub fn insert(&mut self, name: &'a str) { self.0.args.insert(name, MatchedArg::new()); }
+
+ pub fn contains(&self, arg: &str) -> bool { self.0.args.contains_key(arg) }
+
+ pub fn is_empty(&self) -> bool { self.0.args.is_empty() }
+
+ pub fn usage(&mut self, usage: String) { self.0.usage = Some(usage); }
+
+ pub fn arg_names(&'a self) -> Vec<&'a str> { self.0.args.keys().map(Deref::deref).collect() }
+
+ pub fn entry(&mut self, arg: &'a str) -> Entry<&'a str, MatchedArg> { self.0.args.entry(arg) }
+
+ pub fn subcommand(&mut self, sc: SubCommand<'a>) { self.0.subcommand = Some(Box::new(sc)); }
+
+ pub fn subcommand_name(&self) -> Option<&str> { self.0.subcommand_name() }
+
+ pub fn iter(&self) -> Iter<&str, MatchedArg> { self.0.args.iter() }
+
+ pub fn inc_occurrence_of(&mut self, arg: &'a str) {
+ debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg);
+ if let Some(a) = self.get_mut(arg) {
+ a.occurs += 1;
+ return;
+ }
+ debugln!("ArgMatcher::inc_occurrence_of: first instance");
+ self.insert(arg);
+ }
+
+ pub fn inc_occurrences_of(&mut self, args: &[&'a str]) {
+ debugln!("ArgMatcher::inc_occurrences_of: args={:?}", args);
+ for arg in args {
+ self.inc_occurrence_of(arg);
+ }
+ }
+
+ pub fn add_val_to(&mut self, arg: &'a str, val: &OsStr) {
+ let ma = self.entry(arg).or_insert(MatchedArg {
+ occurs: 0,
+ indices: Vec::with_capacity(1),
+ vals: Vec::with_capacity(1),
+ });
+ ma.vals.push(val.to_owned());
+ }
+
+ pub fn add_index_to(&mut self, arg: &'a str, idx: usize) {
+ let ma = self.entry(arg).or_insert(MatchedArg {
+ occurs: 0,
+ indices: Vec::with_capacity(1),
+ vals: Vec::new(),
+ });
+ ma.indices.push(idx);
+ }
+
+ pub fn needs_more_vals<'b, A>(&self, o: &A) -> bool
+ where
+ A: AnyArg<'a, 'b>,
+ {
+ debugln!("ArgMatcher::needs_more_vals: o={}", o.name());
+ if let Some(ma) = self.get(o.name()) {
+ if let Some(num) = o.num_vals() {
+ debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num);
+ return if o.is_set(ArgSettings::Multiple) {
+ ((ma.vals.len() as u64) % num) != 0
+ } else {
+ num != (ma.vals.len() as u64)
+ };
+ } else if let Some(num) = o.max_vals() {
+ debugln!("ArgMatcher::needs_more_vals: max_vals...{}", num);
+ return !((ma.vals.len() as u64) > num);
+ } else if o.min_vals().is_some() {
+ debugln!("ArgMatcher::needs_more_vals: min_vals...true");
+ return true;
+ }
+ return o.is_set(ArgSettings::Multiple);
+ }
+ true
+ }
+}
+
+impl<'a> Into<ArgMatches<'a>> for ArgMatcher<'a> {
+ fn into(self) -> ArgMatches<'a> { self.0 }
+}
diff --git a/clap/src/args/arg_matches.rs b/clap/src/args/arg_matches.rs
new file mode 100644
index 0000000..6cf70a4
--- /dev/null
+++ b/clap/src/args/arg_matches.rs
@@ -0,0 +1,963 @@
+// Std
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::ffi::{OsStr, OsString};
+use std::iter::Map;
+use std::slice::Iter;
+
+// Internal
+use INVALID_UTF8;
+use args::MatchedArg;
+use args::SubCommand;
+
+/// Used to get information about the arguments that where supplied to the program at runtime by
+/// the user. New instances of this struct are obtained by using the [`App::get_matches`] family of
+/// methods.
+///
+/// # Examples
+///
+/// ```no_run
+/// # use clap::{App, Arg};
+/// let matches = App::new("MyApp")
+/// .arg(Arg::with_name("out")
+/// .long("output")
+/// .required(true)
+/// .takes_value(true))
+/// .arg(Arg::with_name("debug")
+/// .short("d")
+/// .multiple(true))
+/// .arg(Arg::with_name("cfg")
+/// .short("c")
+/// .takes_value(true))
+/// .get_matches(); // builds the instance of ArgMatches
+///
+/// // to get information about the "cfg" argument we created, such as the value supplied we use
+/// // various ArgMatches methods, such as ArgMatches::value_of
+/// if let Some(c) = matches.value_of("cfg") {
+/// println!("Value for -c: {}", c);
+/// }
+///
+/// // The ArgMatches::value_of method returns an Option because the user may not have supplied
+/// // that argument at runtime. But if we specified that the argument was "required" as we did
+/// // with the "out" argument, we can safely unwrap because `clap` verifies that was actually
+/// // used at runtime.
+/// println!("Value for --output: {}", matches.value_of("out").unwrap());
+///
+/// // You can check the presence of an argument
+/// if matches.is_present("out") {
+/// // Another way to check if an argument was present, or if it occurred multiple times is to
+/// // use occurrences_of() which returns 0 if an argument isn't found at runtime, or the
+/// // number of times that it occurred, if it was. To allow an argument to appear more than
+/// // once, you must use the .multiple(true) method, otherwise it will only return 1 or 0.
+/// if matches.occurrences_of("debug") > 2 {
+/// println!("Debug mode is REALLY on, don't be crazy");
+/// } else {
+/// println!("Debug mode kind of on");
+/// }
+/// }
+/// ```
+/// [`App::get_matches`]: ./struct.App.html#method.get_matches
+#[derive(Debug, Clone)]
+pub struct ArgMatches<'a> {
+ #[doc(hidden)] pub args: HashMap<&'a str, MatchedArg>,
+ #[doc(hidden)] pub subcommand: Option<Box<SubCommand<'a>>>,
+ #[doc(hidden)] pub usage: Option<String>,
+}
+
+impl<'a> Default for ArgMatches<'a> {
+ fn default() -> Self {
+ ArgMatches {
+ args: HashMap::new(),
+ subcommand: None,
+ usage: None,
+ }
+ }
+}
+
+impl<'a> ArgMatches<'a> {
+ #[doc(hidden)]
+ pub fn new() -> Self {
+ ArgMatches {
+ ..Default::default()
+ }
+ }
+
+ /// Gets the value of a specific [option] or [positional] argument (i.e. an argument that takes
+ /// an additional value at runtime). If the option wasn't present at runtime
+ /// it returns `None`.
+ ///
+ /// *NOTE:* If getting a value for an option or positional argument that allows multiples,
+ /// prefer [`ArgMatches::values_of`] as `ArgMatches::value_of` will only return the *first*
+ /// value.
+ ///
+ /// # Panics
+ ///
+ /// This method will [`panic!`] if the value contains invalid UTF-8 code points.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("output")
+ /// .takes_value(true))
+ /// .get_matches_from(vec!["myapp", "something"]);
+ ///
+ /// assert_eq!(m.value_of("output"), Some("something"));
+ /// ```
+ /// [option]: ./struct.Arg.html#method.takes_value
+ /// [positional]: ./struct.Arg.html#method.index
+ /// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of
+ /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
+ pub fn value_of<S: AsRef<str>>(&self, name: S) -> Option<&str> {
+ if let Some(arg) = self.args.get(name.as_ref()) {
+ if let Some(v) = arg.vals.get(0) {
+ return Some(v.to_str().expect(INVALID_UTF8));
+ }
+ }
+ None
+ }
+
+ /// Gets the lossy value of a specific argument. If the argument wasn't present at runtime
+ /// it returns `None`. A lossy value is one which contains invalid UTF-8 code points, those
+ /// invalid points will be replaced with `\u{FFFD}`
+ ///
+ /// *NOTE:* If getting a value for an option or positional argument that allows multiples,
+ /// prefer [`Arg::values_of_lossy`] as `value_of_lossy()` will only return the *first* value.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```")]
+ /// # use clap::{App, Arg};
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::{OsStrExt,OsStringExt};
+ ///
+ /// let m = App::new("utf8")
+ /// .arg(Arg::from_usage("<arg> 'some arg'"))
+ /// .get_matches_from(vec![OsString::from("myprog"),
+ /// // "Hi {0xe9}!"
+ /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]);
+ /// assert_eq!(&*m.value_of_lossy("arg").unwrap(), "Hi \u{FFFD}!");
+ /// ```
+ /// [`Arg::values_of_lossy`]: ./struct.ArgMatches.html#method.values_of_lossy
+ pub fn value_of_lossy<S: AsRef<str>>(&'a self, name: S) -> Option<Cow<'a, str>> {
+ if let Some(arg) = self.args.get(name.as_ref()) {
+ if let Some(v) = arg.vals.get(0) {
+ return Some(v.to_string_lossy());
+ }
+ }
+ None
+ }
+
+ /// Gets the OS version of a string value of a specific argument. If the option wasn't present
+ /// at runtime it returns `None`. An OS value on Unix-like systems is any series of bytes,
+ /// regardless of whether or not they contain valid UTF-8 code points. Since [`String`]s in
+ /// Rust are guaranteed to be valid UTF-8, a valid filename on a Unix system as an argument
+ /// value may contain invalid UTF-8 code points.
+ ///
+ /// *NOTE:* If getting a value for an option or positional argument that allows multiples,
+ /// prefer [`ArgMatches::values_of_os`] as `Arg::value_of_os` will only return the *first*
+ /// value.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```")]
+ /// # use clap::{App, Arg};
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::{OsStrExt,OsStringExt};
+ ///
+ /// let m = App::new("utf8")
+ /// .arg(Arg::from_usage("<arg> 'some arg'"))
+ /// .get_matches_from(vec![OsString::from("myprog"),
+ /// // "Hi {0xe9}!"
+ /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]);
+ /// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']);
+ /// ```
+ /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
+ /// [`ArgMatches::values_of_os`]: ./struct.ArgMatches.html#method.values_of_os
+ pub fn value_of_os<S: AsRef<str>>(&self, name: S) -> Option<&OsStr> {
+ self.args
+ .get(name.as_ref())
+ .and_then(|arg| arg.vals.get(0).map(|v| v.as_os_str()))
+ }
+
+ /// Gets a [`Values`] struct which implements [`Iterator`] for values of a specific argument
+ /// (i.e. an argument that takes multiple values at runtime). If the option wasn't present at
+ /// runtime it returns `None`
+ ///
+ /// # Panics
+ ///
+ /// This method will panic if any of the values contain invalid UTF-8 code points.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::with_name("output")
+ /// .multiple(true)
+ /// .short("o")
+ /// .takes_value(true))
+ /// .get_matches_from(vec![
+ /// "myprog", "-o", "val1", "val2", "val3"
+ /// ]);
+ /// let vals: Vec<&str> = m.values_of("output").unwrap().collect();
+ /// assert_eq!(vals, ["val1", "val2", "val3"]);
+ /// ```
+ /// [`Values`]: ./struct.Values.html
+ /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
+ pub fn values_of<S: AsRef<str>>(&'a self, name: S) -> Option<Values<'a>> {
+ if let Some(arg) = self.args.get(name.as_ref()) {
+ fn to_str_slice(o: &OsString) -> &str { o.to_str().expect(INVALID_UTF8) }
+ let to_str_slice: fn(&OsString) -> &str = to_str_slice; // coerce to fn pointer
+ return Some(Values {
+ iter: arg.vals.iter().map(to_str_slice),
+ });
+ }
+ None
+ }
+
+ /// Gets the lossy values of a specific argument. If the option wasn't present at runtime
+ /// it returns `None`. A lossy value is one where if it contains invalid UTF-8 code points,
+ /// those invalid points will be replaced with `\u{FFFD}`
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```")]
+ /// # use clap::{App, Arg};
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::OsStringExt;
+ ///
+ /// let m = App::new("utf8")
+ /// .arg(Arg::from_usage("<arg>... 'some arg'"))
+ /// .get_matches_from(vec![OsString::from("myprog"),
+ /// // "Hi"
+ /// OsString::from_vec(vec![b'H', b'i']),
+ /// // "{0xe9}!"
+ /// OsString::from_vec(vec![0xe9, b'!'])]);
+ /// let mut itr = m.values_of_lossy("arg").unwrap().into_iter();
+ /// assert_eq!(&itr.next().unwrap()[..], "Hi");
+ /// assert_eq!(&itr.next().unwrap()[..], "\u{FFFD}!");
+ /// assert_eq!(itr.next(), None);
+ /// ```
+ pub fn values_of_lossy<S: AsRef<str>>(&'a self, name: S) -> Option<Vec<String>> {
+ if let Some(arg) = self.args.get(name.as_ref()) {
+ return Some(
+ arg.vals
+ .iter()
+ .map(|v| v.to_string_lossy().into_owned())
+ .collect(),
+ );
+ }
+ None
+ }
+
+ /// Gets a [`OsValues`] struct which is implements [`Iterator`] for [`OsString`] values of a
+ /// specific argument. If the option wasn't present at runtime it returns `None`. An OS value
+ /// on Unix-like systems is any series of bytes, regardless of whether or not they contain
+ /// valid UTF-8 code points. Since [`String`]s in Rust are guaranteed to be valid UTF-8, a valid
+ /// filename as an argument value on Linux (for example) may contain invalid UTF-8 code points.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```")]
+ /// # use clap::{App, Arg};
+ /// use std::ffi::{OsStr,OsString};
+ /// use std::os::unix::ffi::{OsStrExt,OsStringExt};
+ ///
+ /// let m = App::new("utf8")
+ /// .arg(Arg::from_usage("<arg>... 'some arg'"))
+ /// .get_matches_from(vec![OsString::from("myprog"),
+ /// // "Hi"
+ /// OsString::from_vec(vec![b'H', b'i']),
+ /// // "{0xe9}!"
+ /// OsString::from_vec(vec![0xe9, b'!'])]);
+ ///
+ /// let mut itr = m.values_of_os("arg").unwrap().into_iter();
+ /// assert_eq!(itr.next(), Some(OsStr::new("Hi")));
+ /// assert_eq!(itr.next(), Some(OsStr::from_bytes(&[0xe9, b'!'])));
+ /// assert_eq!(itr.next(), None);
+ /// ```
+ /// [`OsValues`]: ./struct.OsValues.html
+ /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
+ /// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html
+ /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
+ pub fn values_of_os<S: AsRef<str>>(&'a self, name: S) -> Option<OsValues<'a>> {
+ fn to_str_slice(o: &OsString) -> &OsStr { &*o }
+ let to_str_slice: fn(&'a OsString) -> &'a OsStr = to_str_slice; // coerce to fn pointer
+ if let Some(arg) = self.args.get(name.as_ref()) {
+ return Some(OsValues {
+ iter: arg.vals.iter().map(to_str_slice),
+ });
+ }
+ None
+ }
+
+ /// Returns `true` if an argument was present at runtime, otherwise `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::with_name("debug")
+ /// .short("d"))
+ /// .get_matches_from(vec![
+ /// "myprog", "-d"
+ /// ]);
+ ///
+ /// assert!(m.is_present("debug"));
+ /// ```
+ pub fn is_present<S: AsRef<str>>(&self, name: S) -> bool {
+ if let Some(ref sc) = self.subcommand {
+ if sc.name == name.as_ref() {
+ return true;
+ }
+ }
+ self.args.contains_key(name.as_ref())
+ }
+
+ /// Returns the number of times an argument was used at runtime. If an argument isn't present
+ /// it will return `0`.
+ ///
+ /// **NOTE:** This returns the number of times the argument was used, *not* the number of
+ /// values. For example, `-o val1 val2 val3 -o val4` would return `2` (2 occurrences, but 4
+ /// values).
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::with_name("debug")
+ /// .short("d")
+ /// .multiple(true))
+ /// .get_matches_from(vec![
+ /// "myprog", "-d", "-d", "-d"
+ /// ]);
+ ///
+ /// assert_eq!(m.occurrences_of("debug"), 3);
+ /// ```
+ ///
+ /// This next example shows that counts actual uses of the argument, not just `-`'s
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::with_name("debug")
+ /// .short("d")
+ /// .multiple(true))
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .get_matches_from(vec![
+ /// "myprog", "-ddfd"
+ /// ]);
+ ///
+ /// assert_eq!(m.occurrences_of("debug"), 3);
+ /// assert_eq!(m.occurrences_of("flag"), 1);
+ /// ```
+ pub fn occurrences_of<S: AsRef<str>>(&self, name: S) -> u64 {
+ self.args.get(name.as_ref()).map_or(0, |a| a.occurs)
+ }
+
+ /// Gets the starting index of the argument in respect to all other arguments. Indices are
+ /// similar to argv indices, but are not exactly 1:1.
+ ///
+ /// For flags (i.e. those arguments which don't have an associated value), indices refer
+ /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices
+ /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the
+ /// index for `val` would be recorded. This is by design.
+ ///
+ /// Besides the flag/option descrepancy, the primary difference between an argv index and clap
+ /// index, is that clap continues counting once all arguments have properly seperated, whereas
+ /// an argv index does not.
+ ///
+ /// The examples should clear this up.
+ ///
+ /// *NOTE:* If an argument is allowed multiple times, this method will only give the *first*
+ /// index.
+ ///
+ /// # Examples
+ ///
+ /// The argv indices are listed in the comments below. See how they correspond to the clap
+ /// indices. Note that if it's not listed in a clap index, this is becuase it's not saved in
+ /// in an `ArgMatches` struct for querying.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("option")
+ /// .short("o")
+ /// .takes_value(true))
+ /// .get_matches_from(vec!["myapp", "-f", "-o", "val"]);
+ /// // ARGV idices: ^0 ^1 ^2 ^3
+ /// // clap idices: ^1 ^3
+ ///
+ /// assert_eq!(m.index_of("flag"), Some(1));
+ /// assert_eq!(m.index_of("option"), Some(3));
+ /// ```
+ ///
+ /// Now notice, if we use one of the other styles of options:
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("option")
+ /// .short("o")
+ /// .takes_value(true))
+ /// .get_matches_from(vec!["myapp", "-f", "-o=val"]);
+ /// // ARGV idices: ^0 ^1 ^2
+ /// // clap idices: ^1 ^3
+ ///
+ /// assert_eq!(m.index_of("flag"), Some(1));
+ /// assert_eq!(m.index_of("option"), Some(3));
+ /// ```
+ ///
+ /// Things become much more complicated, or clear if we look at a more complex combination of
+ /// flags. Let's also throw in the final option style for good measure.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("flag2")
+ /// .short("F"))
+ /// .arg(Arg::with_name("flag3")
+ /// .short("z"))
+ /// .arg(Arg::with_name("option")
+ /// .short("o")
+ /// .takes_value(true))
+ /// .get_matches_from(vec!["myapp", "-fzF", "-oval"]);
+ /// // ARGV idices: ^0 ^1 ^2
+ /// // clap idices: ^1,2,3 ^5
+ /// //
+ /// // clap sees the above as 'myapp -f -z -F -o val'
+ /// // ^0 ^1 ^2 ^3 ^4 ^5
+ /// assert_eq!(m.index_of("flag"), Some(1));
+ /// assert_eq!(m.index_of("flag2"), Some(3));
+ /// assert_eq!(m.index_of("flag3"), Some(2));
+ /// assert_eq!(m.index_of("option"), Some(5));
+ /// ```
+ ///
+ /// One final combination of flags/options to see how they combine:
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("flag2")
+ /// .short("F"))
+ /// .arg(Arg::with_name("flag3")
+ /// .short("z"))
+ /// .arg(Arg::with_name("option")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .multiple(true))
+ /// .get_matches_from(vec!["myapp", "-fzFoval"]);
+ /// // ARGV idices: ^0 ^1
+ /// // clap idices: ^1,2,3^5
+ /// //
+ /// // clap sees the above as 'myapp -f -z -F -o val'
+ /// // ^0 ^1 ^2 ^3 ^4 ^5
+ /// assert_eq!(m.index_of("flag"), Some(1));
+ /// assert_eq!(m.index_of("flag2"), Some(3));
+ /// assert_eq!(m.index_of("flag3"), Some(2));
+ /// assert_eq!(m.index_of("option"), Some(5));
+ /// ```
+ ///
+ /// The last part to mention is when values are sent in multiple groups with a [delimiter].
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("option")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .multiple(true))
+ /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
+ /// // ARGV idices: ^0 ^1
+ /// // clap idices: ^2 ^3 ^4
+ /// //
+ /// // clap sees the above as 'myapp -o val1 val2 val3'
+ /// // ^0 ^1 ^2 ^3 ^4
+ /// assert_eq!(m.index_of("option"), Some(2));
+ /// ```
+ /// [`ArgMatches`]: ./struct.ArgMatches.html
+ /// [delimiter]: ./struct.Arg.html#method.value_delimiter
+ pub fn index_of<S: AsRef<str>>(&self, name: S) -> Option<usize> {
+ if let Some(arg) = self.args.get(name.as_ref()) {
+ if let Some(i) = arg.indices.get(0) {
+ return Some(*i);
+ }
+ }
+ None
+ }
+
+ /// Gets all indices of the argument in respect to all other arguments. Indices are
+ /// similar to argv indices, but are not exactly 1:1.
+ ///
+ /// For flags (i.e. those arguments which don't have an associated value), indices refer
+ /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices
+ /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the
+ /// index for `val` would be recorded. This is by design.
+ ///
+ /// *NOTE:* For more information about how clap indices compare to argv indices, see
+ /// [`ArgMatches::index_of`]
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("option")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .use_delimiter(true)
+ /// .multiple(true))
+ /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
+ /// // ARGV idices: ^0 ^1
+ /// // clap idices: ^2 ^3 ^4
+ /// //
+ /// // clap sees the above as 'myapp -o val1 val2 val3'
+ /// // ^0 ^1 ^2 ^3 ^4
+ /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
+ /// ```
+ ///
+ /// Another quick example is when flags and options are used together
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("option")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .multiple(true))
+ /// .arg(Arg::with_name("flag")
+ /// .short("f")
+ /// .multiple(true))
+ /// .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]);
+ /// // ARGV idices: ^0 ^1 ^2 ^3 ^4 ^5 ^6
+ /// // clap idices: ^2 ^3 ^5 ^6
+ ///
+ /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
+ /// assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[3, 6]);
+ /// ```
+ ///
+ /// One final example, which is an odd case; if we *don't* use value delimiter as we did with
+ /// the first example above instead of `val1`, `val2` and `val3` all being distinc values, they
+ /// would all be a single value of `val1,val2,val3`, in which case case they'd only receive a
+ /// single index.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg};
+ /// let m = App::new("myapp")
+ /// .arg(Arg::with_name("option")
+ /// .short("o")
+ /// .takes_value(true)
+ /// .multiple(true))
+ /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
+ /// // ARGV idices: ^0 ^1
+ /// // clap idices: ^2
+ /// //
+ /// // clap sees the above as 'myapp -o "val1,val2,val3"'
+ /// // ^0 ^1 ^2
+ /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]);
+ /// ```
+ /// [`ArgMatches`]: ./struct.ArgMatches.html
+ /// [`ArgMatches::index_of`]: ./struct.ArgMatches.html#method.index_of
+ /// [delimiter]: ./struct.Arg.html#method.value_delimiter
+ pub fn indices_of<S: AsRef<str>>(&'a self, name: S) -> Option<Indices<'a>> {
+ if let Some(arg) = self.args.get(name.as_ref()) {
+ fn to_usize(i: &usize) -> usize { *i }
+ let to_usize: fn(&usize) -> usize = to_usize; // coerce to fn pointer
+ return Some(Indices {
+ iter: arg.indices.iter().map(to_usize),
+ });
+ }
+ None
+ }
+
+ /// Because [`Subcommand`]s are essentially "sub-[`App`]s" they have their own [`ArgMatches`]
+ /// as well. This method returns the [`ArgMatches`] for a particular subcommand or `None` if
+ /// the subcommand wasn't present at runtime.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, SubCommand};
+ /// let app_m = App::new("myprog")
+ /// .arg(Arg::with_name("debug")
+ /// .short("d"))
+ /// .subcommand(SubCommand::with_name("test")
+ /// .arg(Arg::with_name("opt")
+ /// .long("option")
+ /// .takes_value(true)))
+ /// .get_matches_from(vec![
+ /// "myprog", "-d", "test", "--option", "val"
+ /// ]);
+ ///
+ /// // Both parent commands, and child subcommands can have arguments present at the same times
+ /// assert!(app_m.is_present("debug"));
+ ///
+ /// // Get the subcommand's ArgMatches instance
+ /// if let Some(sub_m) = app_m.subcommand_matches("test") {
+ /// // Use the struct like normal
+ /// assert_eq!(sub_m.value_of("opt"), Some("val"));
+ /// }
+ /// ```
+ /// [`Subcommand`]: ./struct.SubCommand.html
+ /// [`App`]: ./struct.App.html
+ /// [`ArgMatches`]: ./struct.ArgMatches.html
+ pub fn subcommand_matches<S: AsRef<str>>(&self, name: S) -> Option<&ArgMatches<'a>> {
+ if let Some(ref s) = self.subcommand {
+ if s.name == name.as_ref() {
+ return Some(&s.matches);
+ }
+ }
+ None
+ }
+
+ /// Because [`Subcommand`]s are essentially "sub-[`App`]s" they have their own [`ArgMatches`]
+ /// as well.But simply getting the sub-[`ArgMatches`] doesn't help much if we don't also know
+ /// which subcommand was actually used. This method returns the name of the subcommand that was
+ /// used at runtime, or `None` if one wasn't.
+ ///
+ /// *NOTE*: Subcommands form a hierarchy, where multiple subcommands can be used at runtime,
+ /// but only a single subcommand from any group of sibling commands may used at once.
+ ///
+ /// An ASCII art depiction may help explain this better...Using a fictional version of `git` as
+ /// the demo subject. Imagine the following are all subcommands of `git` (note, the author is
+ /// aware these aren't actually all subcommands in the real `git` interface, but it makes
+ /// explanation easier)
+ ///
+ /// ```notrust
+ /// Top Level App (git) TOP
+ /// |
+ /// -----------------------------------------
+ /// / | \ \
+ /// clone push add commit LEVEL 1
+ /// | / \ / \ |
+ /// url origin remote ref name message LEVEL 2
+ /// / /\
+ /// path remote local LEVEL 3
+ /// ```
+ ///
+ /// Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all
+ /// inclusive list, and not including argument options per command for brevity and clarity):
+ ///
+ /// ```sh
+ /// $ git clone url
+ /// $ git push origin path
+ /// $ git add ref local
+ /// $ git commit message
+ /// ```
+ ///
+ /// Notice only one command per "level" may be used. You could not, for example, do `$ git
+ /// clone url push origin path`
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand};
+ /// let app_m = App::new("git")
+ /// .subcommand(SubCommand::with_name("clone"))
+ /// .subcommand(SubCommand::with_name("push"))
+ /// .subcommand(SubCommand::with_name("commit"))
+ /// .get_matches();
+ ///
+ /// match app_m.subcommand_name() {
+ /// Some("clone") => {}, // clone was used
+ /// Some("push") => {}, // push was used
+ /// Some("commit") => {}, // commit was used
+ /// _ => {}, // Either no subcommand or one not tested for...
+ /// }
+ /// ```
+ /// [`Subcommand`]: ./struct.SubCommand.html
+ /// [`App`]: ./struct.App.html
+ /// [`ArgMatches`]: ./struct.ArgMatches.html
+ pub fn subcommand_name(&self) -> Option<&str> {
+ self.subcommand.as_ref().map(|sc| &sc.name[..])
+ }
+
+ /// This brings together [`ArgMatches::subcommand_matches`] and [`ArgMatches::subcommand_name`]
+ /// by returning a tuple with both pieces of information.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand};
+ /// let app_m = App::new("git")
+ /// .subcommand(SubCommand::with_name("clone"))
+ /// .subcommand(SubCommand::with_name("push"))
+ /// .subcommand(SubCommand::with_name("commit"))
+ /// .get_matches();
+ ///
+ /// match app_m.subcommand() {
+ /// ("clone", Some(sub_m)) => {}, // clone was used
+ /// ("push", Some(sub_m)) => {}, // push was used
+ /// ("commit", Some(sub_m)) => {}, // commit was used
+ /// _ => {}, // Either no subcommand or one not tested for...
+ /// }
+ /// ```
+ ///
+ /// Another useful scenario is when you want to support third party, or external, subcommands.
+ /// In these cases you can't know the subcommand name ahead of time, so use a variable instead
+ /// with pattern matching!
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings};
+ /// // Assume there is an external subcommand named "subcmd"
+ /// let app_m = App::new("myprog")
+ /// .setting(AppSettings::AllowExternalSubcommands)
+ /// .get_matches_from(vec![
+ /// "myprog", "subcmd", "--option", "value", "-fff", "--flag"
+ /// ]);
+ ///
+ /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty
+ /// // string argument name
+ /// match app_m.subcommand() {
+ /// (external, Some(sub_m)) => {
+ /// let ext_args: Vec<&str> = sub_m.values_of("").unwrap().collect();
+ /// assert_eq!(external, "subcmd");
+ /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
+ /// },
+ /// _ => {},
+ /// }
+ /// ```
+ /// [`ArgMatches::subcommand_matches`]: ./struct.ArgMatches.html#method.subcommand_matches
+ /// [`ArgMatches::subcommand_name`]: ./struct.ArgMatches.html#method.subcommand_name
+ pub fn subcommand(&self) -> (&str, Option<&ArgMatches<'a>>) {
+ self.subcommand
+ .as_ref()
+ .map_or(("", None), |sc| (&sc.name[..], Some(&sc.matches)))
+ }
+
+ /// Returns a string slice of the usage statement for the [`App`] or [`SubCommand`]
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use clap::{App, Arg, SubCommand};
+ /// let app_m = App::new("myprog")
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches();
+ ///
+ /// println!("{}", app_m.usage());
+ /// ```
+ /// [`Subcommand`]: ./struct.SubCommand.html
+ /// [`App`]: ./struct.App.html
+ pub fn usage(&self) -> &str { self.usage.as_ref().map_or("", |u| &u[..]) }
+}
+
+
+// The following were taken and adapated from vec_map source
+// repo: https://github.com/contain-rs/vec-map
+// commit: be5e1fa3c26e351761b33010ddbdaf5f05dbcc33
+// license: MIT - Copyright (c) 2015 The Rust Project Developers
+
+/// An iterator for getting multiple values out of an argument via the [`ArgMatches::values_of`]
+/// method.
+///
+/// # Examples
+///
+/// ```rust
+/// # use clap::{App, Arg};
+/// let m = App::new("myapp")
+/// .arg(Arg::with_name("output")
+/// .short("o")
+/// .multiple(true)
+/// .takes_value(true))
+/// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]);
+///
+/// let mut values = m.values_of("output").unwrap();
+///
+/// assert_eq!(values.next(), Some("val1"));
+/// assert_eq!(values.next(), Some("val2"));
+/// assert_eq!(values.next(), None);
+/// ```
+/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of
+#[derive(Debug, Clone)]
+pub struct Values<'a> {
+ iter: Map<Iter<'a, OsString>, fn(&'a OsString) -> &'a str>,
+}
+
+impl<'a> Iterator for Values<'a> {
+ type Item = &'a str;
+
+ fn next(&mut self) -> Option<&'a str> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl<'a> DoubleEndedIterator for Values<'a> {
+ fn next_back(&mut self) -> Option<&'a str> { self.iter.next_back() }
+}
+
+impl<'a> ExactSizeIterator for Values<'a> {}
+
+/// Creates an empty iterator.
+impl<'a> Default for Values<'a> {
+ fn default() -> Self {
+ static EMPTY: [OsString; 0] = [];
+ // This is never called because the iterator is empty:
+ fn to_str_slice(_: &OsString) -> &str { unreachable!() };
+ Values {
+ iter: EMPTY[..].iter().map(to_str_slice),
+ }
+ }
+}
+
+/// An iterator for getting multiple values out of an argument via the [`ArgMatches::values_of_os`]
+/// method. Usage of this iterator allows values which contain invalid UTF-8 code points unlike
+/// [`Values`].
+///
+/// # Examples
+///
+#[cfg_attr(not(unix), doc = " ```ignore")]
+#[cfg_attr(unix, doc = " ```")]
+/// # use clap::{App, Arg};
+/// use std::ffi::OsString;
+/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
+///
+/// let m = App::new("utf8")
+/// .arg(Arg::from_usage("<arg> 'some arg'"))
+/// .get_matches_from(vec![OsString::from("myprog"),
+/// // "Hi {0xe9}!"
+/// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]);
+/// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']);
+/// ```
+/// [`ArgMatches::values_of_os`]: ./struct.ArgMatches.html#method.values_of_os
+/// [`Values`]: ./struct.Values.html
+#[derive(Debug, Clone)]
+pub struct OsValues<'a> {
+ iter: Map<Iter<'a, OsString>, fn(&'a OsString) -> &'a OsStr>,
+}
+
+impl<'a> Iterator for OsValues<'a> {
+ type Item = &'a OsStr;
+
+ fn next(&mut self) -> Option<&'a OsStr> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl<'a> DoubleEndedIterator for OsValues<'a> {
+ fn next_back(&mut self) -> Option<&'a OsStr> { self.iter.next_back() }
+}
+
+impl<'a> ExactSizeIterator for OsValues<'a> {}
+
+/// Creates an empty iterator.
+impl<'a> Default for OsValues<'a> {
+ fn default() -> Self {
+ static EMPTY: [OsString; 0] = [];
+ // This is never called because the iterator is empty:
+ fn to_str_slice(_: &OsString) -> &OsStr { unreachable!() };
+ OsValues {
+ iter: EMPTY[..].iter().map(to_str_slice),
+ }
+ }
+}
+
+/// An iterator for getting multiple indices out of an argument via the [`ArgMatches::indices_of`]
+/// method.
+///
+/// # Examples
+///
+/// ```rust
+/// # use clap::{App, Arg};
+/// let m = App::new("myapp")
+/// .arg(Arg::with_name("output")
+/// .short("o")
+/// .multiple(true)
+/// .takes_value(true))
+/// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]);
+///
+/// let mut indices = m.indices_of("output").unwrap();
+///
+/// assert_eq!(indices.next(), Some(2));
+/// assert_eq!(indices.next(), Some(3));
+/// assert_eq!(indices.next(), None);
+/// ```
+/// [`ArgMatches::indices_of`]: ./struct.ArgMatches.html#method.indices_of
+#[derive(Debug, Clone)]
+pub struct Indices<'a> { // would rather use '_, but: https://github.com/rust-lang/rust/issues/48469
+ iter: Map<Iter<'a, usize>, fn(&'a usize) -> usize>,
+}
+
+impl<'a> Iterator for Indices<'a> {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<usize> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl<'a> DoubleEndedIterator for Indices<'a> {
+ fn next_back(&mut self) -> Option<usize> { self.iter.next_back() }
+}
+
+impl<'a> ExactSizeIterator for Indices<'a> {}
+
+/// Creates an empty iterator.
+impl<'a> Default for Indices<'a> {
+ fn default() -> Self {
+ static EMPTY: [usize; 0] = [];
+ // This is never called because the iterator is empty:
+ fn to_usize(_: &usize) -> usize { unreachable!() };
+ Indices {
+ iter: EMPTY[..].iter().map(to_usize),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_default_values() {
+ let mut values: Values = Values::default();
+ assert_eq!(values.next(), None);
+ }
+
+ #[test]
+ fn test_default_values_with_shorter_lifetime() {
+ let matches = ArgMatches::new();
+ let mut values = matches.values_of("").unwrap_or_default();
+ assert_eq!(values.next(), None);
+ }
+
+ #[test]
+ fn test_default_osvalues() {
+ let mut values: OsValues = OsValues::default();
+ assert_eq!(values.next(), None);
+ }
+
+ #[test]
+ fn test_default_osvalues_with_shorter_lifetime() {
+ let matches = ArgMatches::new();
+ let mut values = matches.values_of_os("").unwrap_or_default();
+ assert_eq!(values.next(), None);
+ }
+
+ #[test]
+ fn test_default_indices() {
+ let mut indices: Indices = Indices::default();
+ assert_eq!(indices.next(), None);
+ }
+
+ #[test]
+ fn test_default_indices_with_shorter_lifetime() {
+ let matches = ArgMatches::new();
+ let mut indices = matches.indices_of("").unwrap_or_default();
+ assert_eq!(indices.next(), None);
+ }
+}
diff --git a/clap/src/args/group.rs b/clap/src/args/group.rs
new file mode 100644
index 0000000..f8bfb7a
--- /dev/null
+++ b/clap/src/args/group.rs
@@ -0,0 +1,635 @@
+#[cfg(feature = "yaml")]
+use std::collections::BTreeMap;
+use std::fmt::{Debug, Formatter, Result};
+
+#[cfg(feature = "yaml")]
+use yaml_rust::Yaml;
+
+/// `ArgGroup`s are a family of related [arguments] and way for you to express, "Any of these
+/// arguments". By placing arguments in a logical group, you can create easier requirement and
+/// exclusion rules instead of having to list each argument individually, or when you want a rule
+/// to apply "any but not all" arguments.
+///
+/// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is
+/// set, this means that at least one argument from that group must be present. If
+/// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present.
+///
+/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for
+/// another argument, meaning any of the arguments that belong to that group will cause a failure
+/// if present, or must present respectively.
+///
+/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
+/// present out of a given set. Imagine that you had multiple arguments, and you want one of them
+/// to be required, but making all of them required isn't feasible because perhaps they conflict
+/// with each other. For example, lets say that you were building an application where one could
+/// set a given version number by supplying a string with an option argument, i.e.
+/// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number
+/// and simply incrementing one of the three numbers. So you create three flags `--major`,
+/// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to
+/// specify that *at least one* of them is used. For this, you can create a group.
+///
+/// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care
+/// exactly which argument was actually used at runtime.
+///
+/// # Examples
+///
+/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of
+/// the arguments from the specified group is present at runtime.
+///
+/// ```rust
+/// # use clap::{App, ArgGroup, ErrorKind};
+/// let result = App::new("app")
+/// .args_from_usage(
+/// "--set-ver [ver] 'set the version manually'
+/// --major 'auto increase major'
+/// --minor 'auto increase minor'
+/// --patch 'auto increase patch'")
+/// .group(ArgGroup::with_name("vers")
+/// .args(&["set-ver", "major", "minor", "patch"])
+/// .required(true))
+/// .get_matches_from_safe(vec!["app", "--major", "--patch"]);
+/// // Because we used two args in the group it's an error
+/// assert!(result.is_err());
+/// let err = result.unwrap_err();
+/// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+/// ```
+/// This next example shows a passing parse of the same scenario
+///
+/// ```rust
+/// # use clap::{App, ArgGroup};
+/// let result = App::new("app")
+/// .args_from_usage(
+/// "--set-ver [ver] 'set the version manually'
+/// --major 'auto increase major'
+/// --minor 'auto increase minor'
+/// --patch 'auto increase patch'")
+/// .group(ArgGroup::with_name("vers")
+/// .args(&["set-ver", "major", "minor","patch"])
+/// .required(true))
+/// .get_matches_from_safe(vec!["app", "--major"]);
+/// assert!(result.is_ok());
+/// let matches = result.unwrap();
+/// // We may not know which of the args was used, so we can test for the group...
+/// assert!(matches.is_present("vers"));
+/// // we could also alternatively check each arg individually (not shown here)
+/// ```
+/// [`ArgGroup::multiple(true)`]: ./struct.ArgGroup.html#method.multiple
+/// [arguments]: ./struct.Arg.html
+/// [conflict]: ./struct.Arg.html#method.conflicts_with
+/// [requirement]: ./struct.Arg.html#method.requires
+#[derive(Default)]
+pub struct ArgGroup<'a> {
+ #[doc(hidden)] pub name: &'a str,
+ #[doc(hidden)] pub args: Vec<&'a str>,
+ #[doc(hidden)] pub required: bool,
+ #[doc(hidden)] pub requires: Option<Vec<&'a str>>,
+ #[doc(hidden)] pub conflicts: Option<Vec<&'a str>>,
+ #[doc(hidden)] pub multiple: bool,
+}
+
+impl<'a> ArgGroup<'a> {
+ /// Creates a new instance of `ArgGroup` using a unique string name. The name will be used to
+ /// get values from the group or refer to the group inside of conflict and requirement rules.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, ArgGroup};
+ /// ArgGroup::with_name("config")
+ /// # ;
+ /// ```
+ pub fn with_name(n: &'a str) -> Self {
+ ArgGroup {
+ name: n,
+ required: false,
+ args: vec![],
+ requires: None,
+ conflicts: None,
+ multiple: false,
+ }
+ }
+
+ /// Creates a new instance of `ArgGroup` from a .yml (YAML) file.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore
+ /// # #[macro_use]
+ /// # extern crate clap;
+ /// # use clap::ArgGroup;
+ /// # fn main() {
+ /// let yml = load_yaml!("group.yml");
+ /// let ag = ArgGroup::from_yaml(yml);
+ /// # }
+ /// ```
+ #[cfg(feature = "yaml")]
+ pub fn from_yaml(y: &'a Yaml) -> ArgGroup<'a> { ArgGroup::from(y.as_hash().unwrap()) }
+
+ /// Adds an [argument] to this group by name
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .arg("flag")
+ /// .arg("color"))
+ /// .get_matches_from(vec!["myprog", "-f"]);
+ /// // maybe we don't know which of the two flags was used...
+ /// assert!(m.is_present("req_flags"));
+ /// // but we can also check individually if needed
+ /// assert!(m.is_present("flag"));
+ /// ```
+ /// [argument]: ./struct.Arg.html
+ #[cfg_attr(feature = "lints", allow(should_assert_eq))]
+ pub fn arg(mut self, n: &'a str) -> Self {
+ assert!(
+ self.name != n,
+ "ArgGroup '{}' can not have same name as arg inside it",
+ &*self.name
+ );
+ self.args.push(n);
+ self
+ }
+
+ /// Adds multiple [arguments] to this group by name
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .args(&["flag", "color"]))
+ /// .get_matches_from(vec!["myprog", "-f"]);
+ /// // maybe we don't know which of the two flags was used...
+ /// assert!(m.is_present("req_flags"));
+ /// // but we can also check individually if needed
+ /// assert!(m.is_present("flag"));
+ /// ```
+ /// [arguments]: ./struct.Arg.html
+ pub fn args(mut self, ns: &[&'a str]) -> Self {
+ for n in ns {
+ self = self.arg(n);
+ }
+ self
+ }
+
+ /// Allows more than one of the ['Arg']s in this group to be used. (Default: `false`)
+ ///
+ /// # Examples
+ ///
+ /// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the
+ /// group
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup};
+ /// let m = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .args(&["flag", "color"])
+ /// .multiple(true))
+ /// .get_matches_from(vec!["myprog", "-f", "-c"]);
+ /// // maybe we don't know which of the two flags was used...
+ /// assert!(m.is_present("req_flags"));
+ /// ```
+ /// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw
+ /// an error if more than one of the args in the group was used.
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup, ErrorKind};
+ /// let result = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .args(&["flag", "color"]))
+ /// .get_matches_from_safe(vec!["myprog", "-f", "-c"]);
+ /// // Because we used both args in the group it's an error
+ /// assert!(result.is_err());
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+ /// ```
+ /// ['Arg']: ./struct.Arg.html
+ pub fn multiple(mut self, m: bool) -> Self {
+ self.multiple = m;
+ self
+ }
+
+ /// Sets the group as required or not. A required group will be displayed in the usage string
+ /// of the application in the format `<arg|arg2|arg3>`. A required `ArgGroup` simply states
+ /// that one argument from this group *must* be present at runtime (unless
+ /// conflicting with another argument).
+ ///
+ /// **NOTE:** This setting only applies to the current [`App`] / [`SubCommand`], and not
+ /// globally.
+ ///
+ /// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with
+ /// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group.
+ /// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which
+ /// states, '*At least* one arg from this group must be used. Using multiple is OK."
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup, ErrorKind};
+ /// let result = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .args(&["flag", "color"])
+ /// .required(true))
+ /// .get_matches_from_safe(vec!["myprog"]);
+ /// // Because we didn't use any of the args in the group, it's an error
+ /// assert!(result.is_err());
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [`App`]: ./struct.App.html
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`ArgGroup::multiple`]: ./struct.ArgGroup.html#method.multiple
+ pub fn required(mut self, r: bool) -> Self {
+ self.required = r;
+ self
+ }
+
+ /// Sets the requirement rules of this group. This is not to be confused with a
+ /// [required group]. Requirement rules function just like [argument requirement rules], you
+ /// can name other arguments or groups that must be present when any one of the arguments from
+ /// this group is used.
+ ///
+ /// **NOTE:** The name provided may be an argument, or group name
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup, ErrorKind};
+ /// let result = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .arg(Arg::with_name("debug")
+ /// .short("d"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .args(&["flag", "color"])
+ /// .requires("debug"))
+ /// .get_matches_from_safe(vec!["myprog", "-c"]);
+ /// // because we used an arg from the group, and the group requires "-d" to be used, it's an
+ /// // error
+ /// assert!(result.is_err());
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [required group]: ./struct.ArgGroup.html#method.required
+ /// [argument requirement rules]: ./struct.Arg.html#method.requires
+ pub fn requires(mut self, n: &'a str) -> Self {
+ if let Some(ref mut reqs) = self.requires {
+ reqs.push(n);
+ } else {
+ self.requires = Some(vec![n]);
+ }
+ self
+ }
+
+ /// Sets the requirement rules of this group. This is not to be confused with a
+ /// [required group]. Requirement rules function just like [argument requirement rules], you
+ /// can name other arguments or groups that must be present when one of the arguments from this
+ /// group is used.
+ ///
+ /// **NOTE:** The names provided may be an argument, or group name
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup, ErrorKind};
+ /// let result = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .arg(Arg::with_name("debug")
+ /// .short("d"))
+ /// .arg(Arg::with_name("verb")
+ /// .short("v"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .args(&["flag", "color"])
+ /// .requires_all(&["debug", "verb"]))
+ /// .get_matches_from_safe(vec!["myprog", "-c", "-d"]);
+ /// // because we used an arg from the group, and the group requires "-d" and "-v" to be used,
+ /// // yet we only used "-d" it's an error
+ /// assert!(result.is_err());
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ /// [required group]: ./struct.ArgGroup.html#method.required
+ /// [argument requirement rules]: ./struct.Arg.html#method.requires_all
+ pub fn requires_all(mut self, ns: &[&'a str]) -> Self {
+ for n in ns {
+ self = self.requires(n);
+ }
+ self
+ }
+
+ /// Sets the exclusion rules of this group. Exclusion (aka conflict) rules function just like
+ /// [argument exclusion rules], you can name other arguments or groups that must *not* be
+ /// present when one of the arguments from this group are used.
+ ///
+ /// **NOTE:** The name provided may be an argument, or group name
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup, ErrorKind};
+ /// let result = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .arg(Arg::with_name("debug")
+ /// .short("d"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .args(&["flag", "color"])
+ /// .conflicts_with("debug"))
+ /// .get_matches_from_safe(vec!["myprog", "-c", "-d"]);
+ /// // because we used an arg from the group, and the group conflicts with "-d", it's an error
+ /// assert!(result.is_err());
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+ /// ```
+ /// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with
+ pub fn conflicts_with(mut self, n: &'a str) -> Self {
+ if let Some(ref mut confs) = self.conflicts {
+ confs.push(n);
+ } else {
+ self.conflicts = Some(vec![n]);
+ }
+ self
+ }
+
+ /// Sets the exclusion rules of this group. Exclusion rules function just like
+ /// [argument exclusion rules], you can name other arguments or groups that must *not* be
+ /// present when one of the arguments from this group are used.
+ ///
+ /// **NOTE:** The names provided may be an argument, or group name
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ArgGroup, ErrorKind};
+ /// let result = App::new("myprog")
+ /// .arg(Arg::with_name("flag")
+ /// .short("f"))
+ /// .arg(Arg::with_name("color")
+ /// .short("c"))
+ /// .arg(Arg::with_name("debug")
+ /// .short("d"))
+ /// .arg(Arg::with_name("verb")
+ /// .short("v"))
+ /// .group(ArgGroup::with_name("req_flags")
+ /// .args(&["flag", "color"])
+ /// .conflicts_with_all(&["debug", "verb"]))
+ /// .get_matches_from_safe(vec!["myprog", "-c", "-v"]);
+ /// // because we used an arg from the group, and the group conflicts with either "-v" or "-d"
+ /// // it's an error
+ /// assert!(result.is_err());
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+ /// ```
+ /// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with_all
+ pub fn conflicts_with_all(mut self, ns: &[&'a str]) -> Self {
+ for n in ns {
+ self = self.conflicts_with(n);
+ }
+ self
+ }
+}
+
+impl<'a> Debug for ArgGroup<'a> {
+ fn fmt(&self, f: &mut Formatter) -> Result {
+ write!(
+ f,
+ "{{\n\
+ \tname: {:?},\n\
+ \targs: {:?},\n\
+ \trequired: {:?},\n\
+ \trequires: {:?},\n\
+ \tconflicts: {:?},\n\
+ }}",
+ self.name,
+ self.args,
+ self.required,
+ self.requires,
+ self.conflicts
+ )
+ }
+}
+
+impl<'a, 'z> From<&'z ArgGroup<'a>> for ArgGroup<'a> {
+ fn from(g: &'z ArgGroup<'a>) -> Self {
+ ArgGroup {
+ name: g.name,
+ required: g.required,
+ args: g.args.clone(),
+ requires: g.requires.clone(),
+ conflicts: g.conflicts.clone(),
+ multiple: g.multiple,
+ }
+ }
+}
+
+#[cfg(feature = "yaml")]
+impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
+ fn from(b: &'a BTreeMap<Yaml, Yaml>) -> Self {
+ // We WANT this to panic on error...so expect() is good.
+ let mut a = ArgGroup::default();
+ let group_settings = if b.len() == 1 {
+ let name_yml = b.keys().nth(0).expect("failed to get name");
+ let name_str = name_yml
+ .as_str()
+ .expect("failed to convert arg YAML name to str");
+ a.name = name_str;
+ b.get(name_yml)
+ .expect("failed to get name_str")
+ .as_hash()
+ .expect("failed to convert to a hash")
+ } else {
+ b
+ };
+
+ for (k, v) in group_settings {
+ a = match k.as_str().unwrap() {
+ "required" => a.required(v.as_bool().unwrap()),
+ "multiple" => a.multiple(v.as_bool().unwrap()),
+ "args" => yaml_vec_or_str!(v, a, arg),
+ "arg" => {
+ if let Some(ys) = v.as_str() {
+ a = a.arg(ys);
+ }
+ a
+ }
+ "requires" => yaml_vec_or_str!(v, a, requires),
+ "conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with),
+ "name" => {
+ if let Some(ys) = v.as_str() {
+ a.name = ys;
+ }
+ a
+ }
+ s => panic!(
+ "Unknown ArgGroup setting '{}' in YAML file for \
+ ArgGroup '{}'",
+ s,
+ a.name
+ ),
+ }
+ }
+
+ a
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::ArgGroup;
+ #[cfg(feature = "yaml")]
+ use yaml_rust::YamlLoader;
+
+ #[test]
+ fn groups() {
+ let g = ArgGroup::with_name("test")
+ .arg("a1")
+ .arg("a4")
+ .args(&["a2", "a3"])
+ .required(true)
+ .conflicts_with("c1")
+ .conflicts_with_all(&["c2", "c3"])
+ .conflicts_with("c4")
+ .requires("r1")
+ .requires_all(&["r2", "r3"])
+ .requires("r4");
+
+ let args = vec!["a1", "a4", "a2", "a3"];
+ let reqs = vec!["r1", "r2", "r3", "r4"];
+ let confs = vec!["c1", "c2", "c3", "c4"];
+
+ assert_eq!(g.args, args);
+ assert_eq!(g.requires, Some(reqs));
+ assert_eq!(g.conflicts, Some(confs));
+ }
+
+ #[test]
+ fn test_debug() {
+ let g = ArgGroup::with_name("test")
+ .arg("a1")
+ .arg("a4")
+ .args(&["a2", "a3"])
+ .required(true)
+ .conflicts_with("c1")
+ .conflicts_with_all(&["c2", "c3"])
+ .conflicts_with("c4")
+ .requires("r1")
+ .requires_all(&["r2", "r3"])
+ .requires("r4");
+
+ let args = vec!["a1", "a4", "a2", "a3"];
+ let reqs = vec!["r1", "r2", "r3", "r4"];
+ let confs = vec!["c1", "c2", "c3", "c4"];
+
+ let debug_str = format!(
+ "{{\n\
+ \tname: \"test\",\n\
+ \targs: {:?},\n\
+ \trequired: {:?},\n\
+ \trequires: {:?},\n\
+ \tconflicts: {:?},\n\
+ }}",
+ args,
+ true,
+ Some(reqs),
+ Some(confs)
+ );
+ assert_eq!(&*format!("{:?}", g), &*debug_str);
+ }
+
+ #[test]
+ fn test_from() {
+ let g = ArgGroup::with_name("test")
+ .arg("a1")
+ .arg("a4")
+ .args(&["a2", "a3"])
+ .required(true)
+ .conflicts_with("c1")
+ .conflicts_with_all(&["c2", "c3"])
+ .conflicts_with("c4")
+ .requires("r1")
+ .requires_all(&["r2", "r3"])
+ .requires("r4");
+
+ let args = vec!["a1", "a4", "a2", "a3"];
+ let reqs = vec!["r1", "r2", "r3", "r4"];
+ let confs = vec!["c1", "c2", "c3", "c4"];
+
+ let g2 = ArgGroup::from(&g);
+ assert_eq!(g2.args, args);
+ assert_eq!(g2.requires, Some(reqs));
+ assert_eq!(g2.conflicts, Some(confs));
+ }
+
+ #[cfg(feature = "yaml")]
+ #[cfg_attr(feature = "yaml", test)]
+ fn test_yaml() {
+ let g_yaml = "name: test
+args:
+- a1
+- a4
+- a2
+- a3
+conflicts_with:
+- c1
+- c2
+- c3
+- c4
+requires:
+- r1
+- r2
+- r3
+- r4";
+ let yml = &YamlLoader::load_from_str(g_yaml).expect("failed to load YAML file")[0];
+ let g = ArgGroup::from_yaml(yml);
+ let args = vec!["a1", "a4", "a2", "a3"];
+ let reqs = vec!["r1", "r2", "r3", "r4"];
+ let confs = vec!["c1", "c2", "c3", "c4"];
+ assert_eq!(g.args, args);
+ assert_eq!(g.requires, Some(reqs));
+ assert_eq!(g.conflicts, Some(confs));
+ }
+}
+
+impl<'a> Clone for ArgGroup<'a> {
+ fn clone(&self) -> Self {
+ ArgGroup {
+ name: self.name,
+ required: self.required,
+ args: self.args.clone(),
+ requires: self.requires.clone(),
+ conflicts: self.conflicts.clone(),
+ multiple: self.multiple,
+ }
+ }
+}
diff --git a/clap/src/args/macros.rs b/clap/src/args/macros.rs
new file mode 100644
index 0000000..1de12f4
--- /dev/null
+++ b/clap/src/args/macros.rs
@@ -0,0 +1,109 @@
+#[cfg(feature = "yaml")]
+macro_rules! yaml_tuple2 {
+ ($a:ident, $v:ident, $c:ident) => {{
+ if let Some(vec) = $v.as_vec() {
+ for ys in vec {
+ if let Some(tup) = ys.as_vec() {
+ debug_assert_eq!(2, tup.len());
+ $a = $a.$c(yaml_str!(tup[0]), yaml_str!(tup[1]));
+ } else {
+ panic!("Failed to convert YAML value to vec");
+ }
+ }
+ } else {
+ panic!("Failed to convert YAML value to vec");
+ }
+ $a
+ }
+ };
+}
+
+#[cfg(feature = "yaml")]
+macro_rules! yaml_tuple3 {
+ ($a:ident, $v:ident, $c:ident) => {{
+ if let Some(vec) = $v.as_vec() {
+ for ys in vec {
+ if let Some(tup) = ys.as_vec() {
+ debug_assert_eq!(3, tup.len());
+ $a = $a.$c(yaml_str!(tup[0]), yaml_opt_str!(tup[1]), yaml_str!(tup[2]));
+ } else {
+ panic!("Failed to convert YAML value to vec");
+ }
+ }
+ } else {
+ panic!("Failed to convert YAML value to vec");
+ }
+ $a
+ }
+ };
+}
+
+#[cfg(feature = "yaml")]
+macro_rules! yaml_vec_or_str {
+ ($v:ident, $a:ident, $c:ident) => {{
+ let maybe_vec = $v.as_vec();
+ if let Some(vec) = maybe_vec {
+ for ys in vec {
+ if let Some(s) = ys.as_str() {
+ $a = $a.$c(s);
+ } else {
+ panic!("Failed to convert YAML value {:?} to a string", ys);
+ }
+ }
+ } else {
+ if let Some(s) = $v.as_str() {
+ $a = $a.$c(s);
+ } else {
+ panic!("Failed to convert YAML value {:?} to either a vec or string", $v);
+ }
+ }
+ $a
+ }
+ };
+}
+
+#[cfg(feature = "yaml")]
+macro_rules! yaml_opt_str {
+ ($v:expr) => {{
+ if $v.is_null() {
+ Some($v.as_str().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)))
+ } else {
+ None
+ }
+ }};
+}
+
+#[cfg(feature = "yaml")]
+macro_rules! yaml_str {
+ ($v:expr) => {{
+ $v.as_str().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))
+ }};
+}
+
+#[cfg(feature = "yaml")]
+macro_rules! yaml_to_str {
+ ($a:ident, $v:ident, $c:ident) => {{
+ $a.$c(yaml_str!($v))
+ }};
+}
+
+#[cfg(feature = "yaml")]
+macro_rules! yaml_to_bool {
+ ($a:ident, $v:ident, $c:ident) => {{
+ $a.$c($v.as_bool().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)))
+ }};
+}
+
+#[cfg(feature = "yaml")]
+macro_rules! yaml_to_u64 {
+ ($a:ident, $v:ident, $c:ident) => {{
+ $a.$c($v.as_i64().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) as u64)
+ }};
+}
+
+#[cfg(feature = "yaml")]
+macro_rules! yaml_to_usize {
+ ($a:ident, $v:ident, $c:ident) => {{
+ $a.$c($v.as_i64().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) as usize)
+ }};
+}
diff --git a/clap/src/args/matched_arg.rs b/clap/src/args/matched_arg.rs
new file mode 100644
index 0000000..eeda261
--- /dev/null
+++ b/clap/src/args/matched_arg.rs
@@ -0,0 +1,24 @@
+// Std
+use std::ffi::OsString;
+
+#[doc(hidden)]
+#[derive(Debug, Clone)]
+pub struct MatchedArg {
+ #[doc(hidden)] pub occurs: u64,
+ #[doc(hidden)] pub indices: Vec<usize>,
+ #[doc(hidden)] pub vals: Vec<OsString>,
+}
+
+impl Default for MatchedArg {
+ fn default() -> Self {
+ MatchedArg {
+ occurs: 1,
+ indices: Vec::new(),
+ vals: Vec::new(),
+ }
+ }
+}
+
+impl MatchedArg {
+ pub fn new() -> Self { MatchedArg::default() }
+}
diff --git a/clap/src/args/mod.rs b/clap/src/args/mod.rs
new file mode 100644
index 0000000..21f9b85
--- /dev/null
+++ b/clap/src/args/mod.rs
@@ -0,0 +1,21 @@
+pub use self::any_arg::{AnyArg, DispOrder};
+pub use self::arg::Arg;
+pub use self::arg_builder::{Base, FlagBuilder, OptBuilder, PosBuilder, Switched, Valued};
+pub use self::arg_matcher::ArgMatcher;
+pub use self::arg_matches::{ArgMatches, OsValues, Values};
+pub use self::group::ArgGroup;
+pub use self::matched_arg::MatchedArg;
+pub use self::settings::{ArgFlags, ArgSettings};
+pub use self::subcommand::SubCommand;
+
+#[macro_use]
+mod macros;
+mod arg;
+pub mod any_arg;
+mod arg_matches;
+mod arg_matcher;
+mod subcommand;
+mod arg_builder;
+mod matched_arg;
+mod group;
+pub mod settings;
diff --git a/clap/src/args/settings.rs b/clap/src/args/settings.rs
new file mode 100644
index 0000000..7b0e0a2
--- /dev/null
+++ b/clap/src/args/settings.rs
@@ -0,0 +1,231 @@
+// Std
+#[allow(deprecated, unused_imports)]
+use std::ascii::AsciiExt;
+use std::str::FromStr;
+
+bitflags! {
+ struct Flags: u32 {
+ const REQUIRED = 1;
+ const MULTIPLE = 1 << 1;
+ const EMPTY_VALS = 1 << 2;
+ const GLOBAL = 1 << 3;
+ const HIDDEN = 1 << 4;
+ const TAKES_VAL = 1 << 5;
+ const USE_DELIM = 1 << 6;
+ const NEXT_LINE_HELP = 1 << 7;
+ const R_UNLESS_ALL = 1 << 8;
+ const REQ_DELIM = 1 << 9;
+ const DELIM_NOT_SET = 1 << 10;
+ const HIDE_POS_VALS = 1 << 11;
+ const ALLOW_TAC_VALS = 1 << 12;
+ const REQUIRE_EQUALS = 1 << 13;
+ const LAST = 1 << 14;
+ const HIDE_DEFAULT_VAL = 1 << 15;
+ const CASE_INSENSITIVE = 1 << 16;
+ const HIDE_ENV_VALS = 1 << 17;
+ const HIDDEN_SHORT_H = 1 << 18;
+ const HIDDEN_LONG_H = 1 << 19;
+ }
+}
+
+#[doc(hidden)]
+#[derive(Debug, Clone, Copy)]
+pub struct ArgFlags(Flags);
+
+impl ArgFlags {
+ pub fn new() -> Self { ArgFlags::default() }
+
+ impl_settings!{ArgSettings,
+ Required => Flags::REQUIRED,
+ Multiple => Flags::MULTIPLE,
+ EmptyValues => Flags::EMPTY_VALS,
+ Global => Flags::GLOBAL,
+ Hidden => Flags::HIDDEN,
+ TakesValue => Flags::TAKES_VAL,
+ UseValueDelimiter => Flags::USE_DELIM,
+ NextLineHelp => Flags::NEXT_LINE_HELP,
+ RequiredUnlessAll => Flags::R_UNLESS_ALL,
+ RequireDelimiter => Flags::REQ_DELIM,
+ ValueDelimiterNotSet => Flags::DELIM_NOT_SET,
+ HidePossibleValues => Flags::HIDE_POS_VALS,
+ AllowLeadingHyphen => Flags::ALLOW_TAC_VALS,
+ RequireEquals => Flags::REQUIRE_EQUALS,
+ Last => Flags::LAST,
+ CaseInsensitive => Flags::CASE_INSENSITIVE,
+ HideEnvValues => Flags::HIDE_ENV_VALS,
+ HideDefaultValue => Flags::HIDE_DEFAULT_VAL,
+ HiddenShortHelp => Flags::HIDDEN_SHORT_H,
+ HiddenLongHelp => Flags::HIDDEN_LONG_H
+ }
+}
+
+impl Default for ArgFlags {
+ fn default() -> Self { ArgFlags(Flags::EMPTY_VALS | Flags::DELIM_NOT_SET) }
+}
+
+/// Various settings that apply to arguments and may be set, unset, and checked via getter/setter
+/// methods [`Arg::set`], [`Arg::unset`], and [`Arg::is_set`]
+///
+/// [`Arg::set`]: ./struct.Arg.html#method.set
+/// [`Arg::unset`]: ./struct.Arg.html#method.unset
+/// [`Arg::is_set`]: ./struct.Arg.html#method.is_set
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum ArgSettings {
+ /// The argument must be used
+ Required,
+ /// The argument may be used multiple times such as `--flag --flag`
+ Multiple,
+ /// The argument allows empty values such as `--option ""`
+ EmptyValues,
+ /// The argument should be propagated down through all child [`SubCommand`]s
+ ///
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ Global,
+ /// The argument should **not** be shown in help text
+ Hidden,
+ /// The argument accepts a value, such as `--option <value>`
+ TakesValue,
+ /// Determines if the argument allows values to be grouped via a delimiter
+ UseValueDelimiter,
+ /// Prints the help text on the line after the argument
+ NextLineHelp,
+ /// Requires the use of a value delimiter for all multiple values
+ RequireDelimiter,
+ /// Hides the possible values from the help string
+ HidePossibleValues,
+ /// Allows vals that start with a '-'
+ AllowLeadingHyphen,
+ /// Require options use `--option=val` syntax
+ RequireEquals,
+ /// Specifies that the arg is the last positional argument and may be accessed early via `--`
+ /// syntax
+ Last,
+ /// Hides the default value from the help string
+ HideDefaultValue,
+ /// Makes `Arg::possible_values` case insensitive
+ CaseInsensitive,
+ /// Hides ENV values in the help message
+ HideEnvValues,
+ /// The argument should **not** be shown in short help text
+ HiddenShortHelp,
+ /// The argument should **not** be shown in long help text
+ HiddenLongHelp,
+ #[doc(hidden)] RequiredUnlessAll,
+ #[doc(hidden)] ValueDelimiterNotSet,
+}
+
+impl FromStr for ArgSettings {
+ type Err = String;
+ fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
+ match &*s.to_ascii_lowercase() {
+ "required" => Ok(ArgSettings::Required),
+ "multiple" => Ok(ArgSettings::Multiple),
+ "global" => Ok(ArgSettings::Global),
+ "emptyvalues" => Ok(ArgSettings::EmptyValues),
+ "hidden" => Ok(ArgSettings::Hidden),
+ "takesvalue" => Ok(ArgSettings::TakesValue),
+ "usevaluedelimiter" => Ok(ArgSettings::UseValueDelimiter),
+ "nextlinehelp" => Ok(ArgSettings::NextLineHelp),
+ "requiredunlessall" => Ok(ArgSettings::RequiredUnlessAll),
+ "requiredelimiter" => Ok(ArgSettings::RequireDelimiter),
+ "valuedelimiternotset" => Ok(ArgSettings::ValueDelimiterNotSet),
+ "hidepossiblevalues" => Ok(ArgSettings::HidePossibleValues),
+ "allowleadinghyphen" => Ok(ArgSettings::AllowLeadingHyphen),
+ "requireequals" => Ok(ArgSettings::RequireEquals),
+ "last" => Ok(ArgSettings::Last),
+ "hidedefaultvalue" => Ok(ArgSettings::HideDefaultValue),
+ "caseinsensitive" => Ok(ArgSettings::CaseInsensitive),
+ "hideenvvalues" => Ok(ArgSettings::HideEnvValues),
+ "hiddenshorthelp" => Ok(ArgSettings::HiddenShortHelp),
+ "hiddenlonghelp" => Ok(ArgSettings::HiddenLongHelp),
+ _ => Err("unknown ArgSetting, cannot convert from str".to_owned()),
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::ArgSettings;
+
+ #[test]
+ fn arg_settings_fromstr() {
+ assert_eq!(
+ "allowleadinghyphen".parse::<ArgSettings>().unwrap(),
+ ArgSettings::AllowLeadingHyphen
+ );
+ assert_eq!(
+ "emptyvalues".parse::<ArgSettings>().unwrap(),
+ ArgSettings::EmptyValues
+ );
+ assert_eq!(
+ "global".parse::<ArgSettings>().unwrap(),
+ ArgSettings::Global
+ );
+ assert_eq!(
+ "hidepossiblevalues".parse::<ArgSettings>().unwrap(),
+ ArgSettings::HidePossibleValues
+ );
+ assert_eq!(
+ "hidden".parse::<ArgSettings>().unwrap(),
+ ArgSettings::Hidden
+ );
+ assert_eq!(
+ "multiple".parse::<ArgSettings>().unwrap(),
+ ArgSettings::Multiple
+ );
+ assert_eq!(
+ "nextlinehelp".parse::<ArgSettings>().unwrap(),
+ ArgSettings::NextLineHelp
+ );
+ assert_eq!(
+ "requiredunlessall".parse::<ArgSettings>().unwrap(),
+ ArgSettings::RequiredUnlessAll
+ );
+ assert_eq!(
+ "requiredelimiter".parse::<ArgSettings>().unwrap(),
+ ArgSettings::RequireDelimiter
+ );
+ assert_eq!(
+ "required".parse::<ArgSettings>().unwrap(),
+ ArgSettings::Required
+ );
+ assert_eq!(
+ "takesvalue".parse::<ArgSettings>().unwrap(),
+ ArgSettings::TakesValue
+ );
+ assert_eq!(
+ "usevaluedelimiter".parse::<ArgSettings>().unwrap(),
+ ArgSettings::UseValueDelimiter
+ );
+ assert_eq!(
+ "valuedelimiternotset".parse::<ArgSettings>().unwrap(),
+ ArgSettings::ValueDelimiterNotSet
+ );
+ assert_eq!(
+ "requireequals".parse::<ArgSettings>().unwrap(),
+ ArgSettings::RequireEquals
+ );
+ assert_eq!("last".parse::<ArgSettings>().unwrap(), ArgSettings::Last);
+ assert_eq!(
+ "hidedefaultvalue".parse::<ArgSettings>().unwrap(),
+ ArgSettings::HideDefaultValue
+ );
+ assert_eq!(
+ "caseinsensitive".parse::<ArgSettings>().unwrap(),
+ ArgSettings::CaseInsensitive
+ );
+ assert_eq!(
+ "hideenvvalues".parse::<ArgSettings>().unwrap(),
+ ArgSettings::HideEnvValues
+ );
+ assert_eq!(
+ "hiddenshorthelp".parse::<ArgSettings>().unwrap(),
+ ArgSettings::HiddenShortHelp
+ );
+ assert_eq!(
+ "hiddenlonghelp".parse::<ArgSettings>().unwrap(),
+ ArgSettings::HiddenLongHelp
+ );
+ assert!("hahahaha".parse::<ArgSettings>().is_err());
+ }
+}
diff --git a/clap/src/args/subcommand.rs b/clap/src/args/subcommand.rs
new file mode 100644
index 0000000..eebbf82
--- /dev/null
+++ b/clap/src/args/subcommand.rs
@@ -0,0 +1,66 @@
+// Third Party
+#[cfg(feature = "yaml")]
+use yaml_rust::Yaml;
+
+// Internal
+use App;
+use ArgMatches;
+
+/// The abstract representation of a command line subcommand.
+///
+/// This struct describes all the valid options of the subcommand for the program. Subcommands are
+/// essentially "sub-[`App`]s" and contain all the same possibilities (such as their own
+/// [arguments], subcommands, and settings).
+///
+/// # Examples
+///
+/// ```rust
+/// # use clap::{App, Arg, SubCommand};
+/// App::new("myprog")
+/// .subcommand(
+/// SubCommand::with_name("config")
+/// .about("Used for configuration")
+/// .arg(Arg::with_name("config_file")
+/// .help("The configuration file to use")
+/// .index(1)))
+/// # ;
+/// ```
+/// [`App`]: ./struct.App.html
+/// [arguments]: ./struct.Arg.html
+#[derive(Debug, Clone)]
+pub struct SubCommand<'a> {
+ #[doc(hidden)] pub name: String,
+ #[doc(hidden)] pub matches: ArgMatches<'a>,
+}
+
+impl<'a> SubCommand<'a> {
+ /// Creates a new instance of a subcommand requiring a name. The name will be displayed
+ /// to the user when they print version or help and usage information.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, SubCommand};
+ /// App::new("myprog")
+ /// .subcommand(
+ /// SubCommand::with_name("config"))
+ /// # ;
+ /// ```
+ pub fn with_name<'b>(name: &str) -> App<'a, 'b> { App::new(name) }
+
+ /// Creates a new instance of a subcommand from a YAML (.yml) document
+ ///
+ /// # Examples
+ ///
+ /// ```ignore
+ /// # #[macro_use]
+ /// # extern crate clap;
+ /// # use clap::Subcommand;
+ /// # fn main() {
+ /// let sc_yaml = load_yaml!("test_subcommand.yml");
+ /// let sc = SubCommand::from_yaml(sc_yaml);
+ /// # }
+ /// ```
+ #[cfg(feature = "yaml")]
+ pub fn from_yaml(yaml: &Yaml) -> App { App::from_yaml(yaml) }
+}
diff --git a/clap/src/completions/bash.rs b/clap/src/completions/bash.rs
new file mode 100644
index 0000000..37dfa66
--- /dev/null
+++ b/clap/src/completions/bash.rs
@@ -0,0 +1,219 @@
+// Std
+use std::io::Write;
+
+// Internal
+use app::parser::Parser;
+use args::OptBuilder;
+use completions;
+
+pub struct BashGen<'a, 'b>
+where
+ 'a: 'b,
+{
+ p: &'b Parser<'a, 'b>,
+}
+
+impl<'a, 'b> BashGen<'a, 'b> {
+ pub fn new(p: &'b Parser<'a, 'b>) -> Self { BashGen { p: p } }
+
+ pub fn generate_to<W: Write>(&self, buf: &mut W) {
+ w!(
+ buf,
+ format!(
+ r#"_{name}() {{
+ local i cur prev opts cmds
+ COMPREPLY=()
+ cur="${{COMP_WORDS[COMP_CWORD]}}"
+ prev="${{COMP_WORDS[COMP_CWORD-1]}}"
+ cmd=""
+ opts=""
+
+ for i in ${{COMP_WORDS[@]}}
+ do
+ case "${{i}}" in
+ {name})
+ cmd="{name}"
+ ;;
+ {subcmds}
+ *)
+ ;;
+ esac
+ done
+
+ case "${{cmd}}" in
+ {name})
+ opts="{name_opts}"
+ if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
+ COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") )
+ return 0
+ fi
+ case "${{prev}}" in
+ {name_opts_details}
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") )
+ return 0
+ ;;
+ {subcmd_details}
+ esac
+}}
+
+complete -F _{name} -o bashdefault -o default {name}
+"#,
+ name = self.p.meta.bin_name.as_ref().unwrap(),
+ name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
+ name_opts_details =
+ self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
+ subcmds = self.all_subcommands(),
+ subcmd_details = self.subcommand_details()
+ ).as_bytes()
+ );
+ }
+
+ fn all_subcommands(&self) -> String {
+ debugln!("BashGen::all_subcommands;");
+ let mut subcmds = String::new();
+ let scs = completions::all_subcommand_names(self.p);
+
+ for sc in &scs {
+ subcmds = format!(
+ r#"{}
+ {name})
+ cmd+="__{fn_name}"
+ ;;"#,
+ subcmds,
+ name = sc,
+ fn_name = sc.replace("-", "__")
+ );
+ }
+
+ subcmds
+ }
+
+ fn subcommand_details(&self) -> String {
+ debugln!("BashGen::subcommand_details;");
+ let mut subcmd_dets = String::new();
+ let mut scs = completions::get_all_subcommand_paths(self.p, true);
+ scs.sort();
+ scs.dedup();
+
+ for sc in &scs {
+ subcmd_dets = format!(
+ r#"{}
+ {subcmd})
+ opts="{sc_opts}"
+ if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
+ COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") )
+ return 0
+ fi
+ case "${{prev}}" in
+ {opts_details}
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") )
+ return 0
+ ;;"#,
+ subcmd_dets,
+ subcmd = sc.replace("-", "__"),
+ sc_opts = self.all_options_for_path(&*sc),
+ level = sc.split("__").map(|_| 1).fold(0, |acc, n| acc + n),
+ opts_details = self.option_details_for_path(&*sc)
+ );
+ }
+
+ subcmd_dets
+ }
+
+ fn option_details_for_path(&self, path: &str) -> String {
+ debugln!("BashGen::option_details_for_path: path={}", path);
+ let mut p = self.p;
+ for sc in path.split("__").skip(1) {
+ debugln!("BashGen::option_details_for_path:iter: sc={}", sc);
+ p = &find_subcmd!(p, sc).unwrap().p;
+ }
+ let mut opts = String::new();
+ for o in p.opts() {
+ if let Some(l) = o.s.long {
+ opts = format!(
+ "{}
+ --{})
+ COMPREPLY=({})
+ return 0
+ ;;",
+ opts,
+ l,
+ self.vals_for(o)
+ );
+ }
+ if let Some(s) = o.s.short {
+ opts = format!(
+ "{}
+ -{})
+ COMPREPLY=({})
+ return 0
+ ;;",
+ opts,
+ s,
+ self.vals_for(o)
+ );
+ }
+ }
+ opts
+ }
+
+ fn vals_for(&self, o: &OptBuilder) -> String {
+ debugln!("BashGen::vals_for: o={}", o.b.name);
+ use args::AnyArg;
+ if let Some(vals) = o.possible_vals() {
+ format!(r#"$(compgen -W "{}" -- "${{cur}}")"#, vals.join(" "))
+ } else {
+ String::from(r#"$(compgen -f "${cur}")"#)
+ }
+ }
+
+ fn all_options_for_path(&self, path: &str) -> String {
+ debugln!("BashGen::all_options_for_path: path={}", path);
+ let mut p = self.p;
+ for sc in path.split("__").skip(1) {
+ debugln!("BashGen::all_options_for_path:iter: sc={}", sc);
+ p = &find_subcmd!(p, sc).unwrap().p;
+ }
+ let mut opts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s));
+ opts = format!(
+ "{} {}",
+ opts,
+ longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l))
+ );
+ opts = format!(
+ "{} {}",
+ opts,
+ p.positionals
+ .values()
+ .fold(String::new(), |acc, p| format!("{} {}", acc, p))
+ );
+ opts = format!(
+ "{} {}",
+ opts,
+ p.subcommands
+ .iter()
+ .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name))
+ );
+ for sc in &p.subcommands {
+ if let Some(ref aliases) = sc.p.meta.aliases {
+ opts = format!(
+ "{} {}",
+ opts,
+ aliases
+ .iter()
+ .map(|&(n, _)| n)
+ .fold(String::new(), |acc, a| format!("{} {}", acc, a))
+ );
+ }
+ }
+ opts
+ }
+}
diff --git a/clap/src/completions/elvish.rs b/clap/src/completions/elvish.rs
new file mode 100644
index 0000000..9a5f21a
--- /dev/null
+++ b/clap/src/completions/elvish.rs
@@ -0,0 +1,126 @@
+// Std
+use std::io::Write;
+
+// Internal
+use app::parser::Parser;
+use INTERNAL_ERROR_MSG;
+
+pub struct ElvishGen<'a, 'b>
+where
+ 'a: 'b,
+{
+ p: &'b Parser<'a, 'b>,
+}
+
+impl<'a, 'b> ElvishGen<'a, 'b> {
+ pub fn new(p: &'b Parser<'a, 'b>) -> Self { ElvishGen { p: p } }
+
+ pub fn generate_to<W: Write>(&self, buf: &mut W) {
+ let bin_name = self.p.meta.bin_name.as_ref().unwrap();
+
+ let mut names = vec![];
+ let subcommands_cases =
+ generate_inner(self.p, "", &mut names);
+
+ let result = format!(r#"
+edit:completion:arg-completer[{bin_name}] = [@words]{{
+ fn spaces [n]{{
+ repeat $n ' ' | joins ''
+ }}
+ fn cand [text desc]{{
+ edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc
+ }}
+ command = '{bin_name}'
+ for word $words[1:-1] {{
+ if (has-prefix $word '-') {{
+ break
+ }}
+ command = $command';'$word
+ }}
+ completions = [{subcommands_cases}
+ ]
+ $completions[$command]
+}}
+"#,
+ bin_name = bin_name,
+ subcommands_cases = subcommands_cases
+ );
+
+ w!(buf, result.as_bytes());
+ }
+}
+
+// Escape string inside single quotes
+fn escape_string(string: &str) -> String { string.replace("'", "''") }
+
+fn get_tooltip<T : ToString>(help: Option<&str>, data: T) -> String {
+ match help {
+ Some(help) => escape_string(help),
+ _ => data.to_string()
+ }
+}
+
+fn generate_inner<'a, 'b, 'p>(
+ p: &'p Parser<'a, 'b>,
+ previous_command_name: &str,
+ names: &mut Vec<&'p str>,
+) -> String {
+ debugln!("ElvishGen::generate_inner;");
+ let command_name = if previous_command_name.is_empty() {
+ p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone()
+ } else {
+ format!("{};{}", previous_command_name, &p.meta.name)
+ };
+
+ let mut completions = String::new();
+ let preamble = String::from("\n cand ");
+
+ for option in p.opts() {
+ if let Some(data) = option.s.short {
+ let tooltip = get_tooltip(option.b.help, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("-{} '{}'", data, tooltip).as_str());
+ }
+ if let Some(data) = option.s.long {
+ let tooltip = get_tooltip(option.b.help, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("--{} '{}'", data, tooltip).as_str());
+ }
+ }
+
+ for flag in p.flags() {
+ if let Some(data) = flag.s.short {
+ let tooltip = get_tooltip(flag.b.help, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("-{} '{}'", data, tooltip).as_str());
+ }
+ if let Some(data) = flag.s.long {
+ let tooltip = get_tooltip(flag.b.help, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("--{} '{}'", data, tooltip).as_str());
+ }
+ }
+
+ for subcommand in &p.subcommands {
+ let data = &subcommand.p.meta.name;
+ let tooltip = get_tooltip(subcommand.p.meta.about, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("{} '{}'", data, tooltip).as_str());
+ }
+
+ let mut subcommands_cases = format!(
+ r"
+ &'{}'= {{{}
+ }}",
+ &command_name,
+ completions
+ );
+
+ for subcommand in &p.subcommands {
+ let subcommand_subcommands_cases =
+ generate_inner(&subcommand.p, &command_name, names);
+ subcommands_cases.push_str(&subcommand_subcommands_cases);
+ }
+
+ subcommands_cases
+}
diff --git a/clap/src/completions/fish.rs b/clap/src/completions/fish.rs
new file mode 100644
index 0000000..c2c5a5e
--- /dev/null
+++ b/clap/src/completions/fish.rs
@@ -0,0 +1,99 @@
+// Std
+use std::io::Write;
+
+// Internal
+use app::parser::Parser;
+
+pub struct FishGen<'a, 'b>
+where
+ 'a: 'b,
+{
+ p: &'b Parser<'a, 'b>,
+}
+
+impl<'a, 'b> FishGen<'a, 'b> {
+ pub fn new(p: &'b Parser<'a, 'b>) -> Self { FishGen { p: p } }
+
+ pub fn generate_to<W: Write>(&self, buf: &mut W) {
+ let command = self.p.meta.bin_name.as_ref().unwrap();
+ let mut buffer = String::new();
+ gen_fish_inner(command, self, command, &mut buffer);
+ w!(buf, buffer.as_bytes());
+ }
+}
+
+// Escape string inside single quotes
+fn escape_string(string: &str) -> String { string.replace("\\", "\\\\").replace("'", "\\'") }
+
+fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, subcommand: &str, buffer: &mut String) {
+ debugln!("FishGen::gen_fish_inner;");
+ // example :
+ //
+ // complete
+ // -c {command}
+ // -d "{description}"
+ // -s {short}
+ // -l {long}
+ // -a "{possible_arguments}"
+ // -r # if require parameter
+ // -f # don't use file completion
+ // -n "__fish_use_subcommand" # complete for command "myprog"
+ // -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1"
+
+ let mut basic_template = format!("complete -c {} -n ", root_command);
+ if root_command == subcommand {
+ basic_template.push_str("\"__fish_use_subcommand\"");
+ } else {
+ basic_template.push_str(format!("\"__fish_seen_subcommand_from {}\"", subcommand).as_str());
+ }
+
+ for option in comp_gen.p.opts() {
+ let mut template = basic_template.clone();
+ if let Some(data) = option.s.short {
+ template.push_str(format!(" -s {}", data).as_str());
+ }
+ if let Some(data) = option.s.long {
+ template.push_str(format!(" -l {}", data).as_str());
+ }
+ if let Some(data) = option.b.help {
+ template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
+ }
+ if let Some(ref data) = option.v.possible_vals {
+ template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str());
+ }
+ buffer.push_str(template.as_str());
+ buffer.push_str("\n");
+ }
+
+ for flag in comp_gen.p.flags() {
+ let mut template = basic_template.clone();
+ if let Some(data) = flag.s.short {
+ template.push_str(format!(" -s {}", data).as_str());
+ }
+ if let Some(data) = flag.s.long {
+ template.push_str(format!(" -l {}", data).as_str());
+ }
+ if let Some(data) = flag.b.help {
+ template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
+ }
+ buffer.push_str(template.as_str());
+ buffer.push_str("\n");
+ }
+
+ for subcommand in &comp_gen.p.subcommands {
+ let mut template = basic_template.clone();
+ template.push_str(" -f");
+ template.push_str(format!(" -a \"{}\"", &subcommand.p.meta.name).as_str());
+ if let Some(data) = subcommand.p.meta.about {
+ template.push_str(format!(" -d '{}'", escape_string(data)).as_str())
+ }
+ buffer.push_str(template.as_str());
+ buffer.push_str("\n");
+ }
+
+ // generate options of subcommands
+ for subcommand in &comp_gen.p.subcommands {
+ let sub_comp_gen = FishGen::new(&subcommand.p);
+ gen_fish_inner(root_command, &sub_comp_gen, &subcommand.to_string(), buffer);
+ }
+}
diff --git a/clap/src/completions/macros.rs b/clap/src/completions/macros.rs
new file mode 100644
index 0000000..653c72c
--- /dev/null
+++ b/clap/src/completions/macros.rs
@@ -0,0 +1,28 @@
+macro_rules! w {
+ ($buf:expr, $to_w:expr) => {
+ match $buf.write_all($to_w) {
+ Ok(..) => (),
+ Err(..) => panic!("Failed to write to completions file"),
+ }
+ };
+}
+
+macro_rules! get_zsh_arg_conflicts {
+ ($p:ident, $arg:ident, $msg:ident) => {
+ if let Some(conf_vec) = $arg.blacklist() {
+ let mut v = vec![];
+ for arg_name in conf_vec {
+ let arg = $p.find_any_arg(arg_name).expect($msg);
+ if let Some(s) = arg.short() {
+ v.push(format!("-{}", s));
+ }
+ if let Some(l) = arg.long() {
+ v.push(format!("--{}", l));
+ }
+ }
+ v.join(" ")
+ } else {
+ String::new()
+ }
+ }
+}
diff --git a/clap/src/completions/mod.rs b/clap/src/completions/mod.rs
new file mode 100644
index 0000000..a3306d7
--- /dev/null
+++ b/clap/src/completions/mod.rs
@@ -0,0 +1,179 @@
+#[macro_use]
+mod macros;
+mod bash;
+mod fish;
+mod zsh;
+mod powershell;
+mod elvish;
+mod shell;
+
+// Std
+use std::io::Write;
+
+// Internal
+use app::parser::Parser;
+use self::bash::BashGen;
+use self::fish::FishGen;
+use self::zsh::ZshGen;
+use self::powershell::PowerShellGen;
+use self::elvish::ElvishGen;
+pub use self::shell::Shell;
+
+pub struct ComplGen<'a, 'b>
+where
+ 'a: 'b,
+{
+ p: &'b Parser<'a, 'b>,
+}
+
+impl<'a, 'b> ComplGen<'a, 'b> {
+ pub fn new(p: &'b Parser<'a, 'b>) -> Self { ComplGen { p: p } }
+
+ pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
+ match for_shell {
+ Shell::Bash => BashGen::new(self.p).generate_to(buf),
+ Shell::Fish => FishGen::new(self.p).generate_to(buf),
+ Shell::Zsh => ZshGen::new(self.p).generate_to(buf),
+ Shell::PowerShell => PowerShellGen::new(self.p).generate_to(buf),
+ Shell::Elvish => ElvishGen::new(self.p).generate_to(buf),
+ }
+ }
+}
+
+// Gets all subcommands including child subcommands in the form of 'name' where the name
+// is a single word (i.e. "install") of the path to said subcommand (i.e.
+// "rustup toolchain install")
+//
+// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
+// aliasing.
+pub fn all_subcommand_names(p: &Parser) -> Vec<String> {
+ debugln!("all_subcommand_names;");
+ let mut subcmds: Vec<_> = subcommands_of(p)
+ .iter()
+ .map(|&(ref n, _)| n.clone())
+ .collect();
+ for sc_v in p.subcommands.iter().map(|s| all_subcommand_names(&s.p)) {
+ subcmds.extend(sc_v);
+ }
+ subcmds.sort();
+ subcmds.dedup();
+ subcmds
+}
+
+// Gets all subcommands including child subcommands in the form of ('name', 'bin_name') where the name
+// is a single word (i.e. "install") of the path and full bin_name of said subcommand (i.e.
+// "rustup toolchain install")
+//
+// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
+// aliasing.
+pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> {
+ debugln!("all_subcommands;");
+ let mut subcmds: Vec<_> = subcommands_of(p);
+ for sc_v in p.subcommands.iter().map(|s| all_subcommands(&s.p)) {
+ subcmds.extend(sc_v);
+ }
+ subcmds
+}
+
+// Gets all subcommands excluding child subcommands in the form of (name, bin_name) where the name
+// is a single word (i.e. "install") and the bin_name is a space delineated list of the path to said
+// subcommand (i.e. "rustup toolchain install")
+//
+// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
+// aliasing.
+pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
+ debugln!(
+ "subcommands_of: name={}, bin_name={}",
+ p.meta.name,
+ p.meta.bin_name.as_ref().unwrap()
+ );
+ let mut subcmds = vec![];
+
+ debugln!(
+ "subcommands_of: Has subcommands...{:?}",
+ p.has_subcommands()
+ );
+ if !p.has_subcommands() {
+ let mut ret = vec![];
+ debugln!("subcommands_of: Looking for aliases...");
+ if let Some(ref aliases) = p.meta.aliases {
+ for &(n, _) in aliases {
+ debugln!("subcommands_of:iter:iter: Found alias...{}", n);
+ let mut als_bin_name: Vec<_> =
+ p.meta.bin_name.as_ref().unwrap().split(' ').collect();
+ als_bin_name.push(n);
+ let old = als_bin_name.len() - 2;
+ als_bin_name.swap_remove(old);
+ ret.push((n.to_owned(), als_bin_name.join(" ")));
+ }
+ }
+ return ret;
+ }
+ for sc in &p.subcommands {
+ debugln!(
+ "subcommands_of:iter: name={}, bin_name={}",
+ sc.p.meta.name,
+ sc.p.meta.bin_name.as_ref().unwrap()
+ );
+
+ debugln!("subcommands_of:iter: Looking for aliases...");
+ if let Some(ref aliases) = sc.p.meta.aliases {
+ for &(n, _) in aliases {
+ debugln!("subcommands_of:iter:iter: Found alias...{}", n);
+ let mut als_bin_name: Vec<_> =
+ p.meta.bin_name.as_ref().unwrap().split(' ').collect();
+ als_bin_name.push(n);
+ let old = als_bin_name.len() - 2;
+ als_bin_name.swap_remove(old);
+ subcmds.push((n.to_owned(), als_bin_name.join(" ")));
+ }
+ }
+ subcmds.push((
+ sc.p.meta.name.clone(),
+ sc.p.meta.bin_name.as_ref().unwrap().clone(),
+ ));
+ }
+ subcmds
+}
+
+pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
+ debugln!("get_all_subcommand_paths;");
+ let mut subcmds = vec![];
+ if !p.has_subcommands() {
+ if !first {
+ let name = &*p.meta.name;
+ let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "__");
+ let mut ret = vec![path.clone()];
+ if let Some(ref aliases) = p.meta.aliases {
+ for &(n, _) in aliases {
+ ret.push(path.replace(name, n));
+ }
+ }
+ return ret;
+ }
+ return vec![];
+ }
+ for sc in &p.subcommands {
+ let name = &*sc.p.meta.name;
+ let path = sc.p
+ .meta
+ .bin_name
+ .as_ref()
+ .unwrap()
+ .clone()
+ .replace(" ", "__");
+ subcmds.push(path.clone());
+ if let Some(ref aliases) = sc.p.meta.aliases {
+ for &(n, _) in aliases {
+ subcmds.push(path.replace(name, n));
+ }
+ }
+ }
+ for sc_v in p.subcommands
+ .iter()
+ .map(|s| get_all_subcommand_paths(&s.p, false))
+ {
+ subcmds.extend(sc_v);
+ }
+ subcmds
+}
diff --git a/clap/src/completions/powershell.rs b/clap/src/completions/powershell.rs
new file mode 100644
index 0000000..9fc77c7
--- /dev/null
+++ b/clap/src/completions/powershell.rs
@@ -0,0 +1,139 @@
+// Std
+use std::io::Write;
+
+// Internal
+use app::parser::Parser;
+use INTERNAL_ERROR_MSG;
+
+pub struct PowerShellGen<'a, 'b>
+where
+ 'a: 'b,
+{
+ p: &'b Parser<'a, 'b>,
+}
+
+impl<'a, 'b> PowerShellGen<'a, 'b> {
+ pub fn new(p: &'b Parser<'a, 'b>) -> Self { PowerShellGen { p: p } }
+
+ pub fn generate_to<W: Write>(&self, buf: &mut W) {
+ let bin_name = self.p.meta.bin_name.as_ref().unwrap();
+
+ let mut names = vec![];
+ let subcommands_cases =
+ generate_inner(self.p, "", &mut names);
+
+ let result = format!(r#"
+using namespace System.Management.Automation
+using namespace System.Management.Automation.Language
+
+Register-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{
+ param($wordToComplete, $commandAst, $cursorPosition)
+
+ $commandElements = $commandAst.CommandElements
+ $command = @(
+ '{bin_name}'
+ for ($i = 1; $i -lt $commandElements.Count; $i++) {{
+ $element = $commandElements[$i]
+ if ($element -isnot [StringConstantExpressionAst] -or
+ $element.StringConstantType -ne [StringConstantType]::BareWord -or
+ $element.Value.StartsWith('-')) {{
+ break
+ }}
+ $element.Value
+ }}) -join ';'
+
+ $completions = @(switch ($command) {{{subcommands_cases}
+ }})
+
+ $completions.Where{{ $_.CompletionText -like "$wordToComplete*" }} |
+ Sort-Object -Property ListItemText
+}}
+"#,
+ bin_name = bin_name,
+ subcommands_cases = subcommands_cases
+ );
+
+ w!(buf, result.as_bytes());
+ }
+}
+
+// Escape string inside single quotes
+fn escape_string(string: &str) -> String { string.replace("'", "''") }
+
+fn get_tooltip<T : ToString>(help: Option<&str>, data: T) -> String {
+ match help {
+ Some(help) => escape_string(help),
+ _ => data.to_string()
+ }
+}
+
+fn generate_inner<'a, 'b, 'p>(
+ p: &'p Parser<'a, 'b>,
+ previous_command_name: &str,
+ names: &mut Vec<&'p str>,
+) -> String {
+ debugln!("PowerShellGen::generate_inner;");
+ let command_name = if previous_command_name.is_empty() {
+ p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone()
+ } else {
+ format!("{};{}", previous_command_name, &p.meta.name)
+ };
+
+ let mut completions = String::new();
+ let preamble = String::from("\n [CompletionResult]::new(");
+
+ for option in p.opts() {
+ if let Some(data) = option.s.short {
+ let tooltip = get_tooltip(option.b.help, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("'-{}', '{}', {}, '{}')",
+ data, data, "[CompletionResultType]::ParameterName", tooltip).as_str());
+ }
+ if let Some(data) = option.s.long {
+ let tooltip = get_tooltip(option.b.help, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("'--{}', '{}', {}, '{}')",
+ data, data, "[CompletionResultType]::ParameterName", tooltip).as_str());
+ }
+ }
+
+ for flag in p.flags() {
+ if let Some(data) = flag.s.short {
+ let tooltip = get_tooltip(flag.b.help, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("'-{}', '{}', {}, '{}')",
+ data, data, "[CompletionResultType]::ParameterName", tooltip).as_str());
+ }
+ if let Some(data) = flag.s.long {
+ let tooltip = get_tooltip(flag.b.help, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("'--{}', '{}', {}, '{}')",
+ data, data, "[CompletionResultType]::ParameterName", tooltip).as_str());
+ }
+ }
+
+ for subcommand in &p.subcommands {
+ let data = &subcommand.p.meta.name;
+ let tooltip = get_tooltip(subcommand.p.meta.about, data);
+ completions.push_str(&preamble);
+ completions.push_str(format!("'{}', '{}', {}, '{}')",
+ data, data, "[CompletionResultType]::ParameterValue", tooltip).as_str());
+ }
+
+ let mut subcommands_cases = format!(
+ r"
+ '{}' {{{}
+ break
+ }}",
+ &command_name,
+ completions
+ );
+
+ for subcommand in &p.subcommands {
+ let subcommand_subcommands_cases =
+ generate_inner(&subcommand.p, &command_name, names);
+ subcommands_cases.push_str(&subcommand_subcommands_cases);
+ }
+
+ subcommands_cases
+}
diff --git a/clap/src/completions/shell.rs b/clap/src/completions/shell.rs
new file mode 100644
index 0000000..19aab86
--- /dev/null
+++ b/clap/src/completions/shell.rs
@@ -0,0 +1,52 @@
+#[allow(deprecated, unused_imports)]
+use std::ascii::AsciiExt;
+use std::str::FromStr;
+use std::fmt;
+
+/// Describes which shell to produce a completions file for
+#[cfg_attr(feature = "lints", allow(enum_variant_names))]
+#[derive(Debug, Copy, Clone)]
+pub enum Shell {
+ /// Generates a .bash completion file for the Bourne Again SHell (BASH)
+ Bash,
+ /// Generates a .fish completion file for the Friendly Interactive SHell (fish)
+ Fish,
+ /// Generates a completion file for the Z SHell (ZSH)
+ Zsh,
+ /// Generates a completion file for PowerShell
+ PowerShell,
+ /// Generates a completion file for Elvish
+ Elvish,
+}
+
+impl Shell {
+ /// A list of possible variants in `&'static str` form
+ pub fn variants() -> [&'static str; 5] { ["zsh", "bash", "fish", "powershell", "elvish"] }
+}
+
+impl FromStr for Shell {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "ZSH" | _ if s.eq_ignore_ascii_case("zsh") => Ok(Shell::Zsh),
+ "FISH" | _ if s.eq_ignore_ascii_case("fish") => Ok(Shell::Fish),
+ "BASH" | _ if s.eq_ignore_ascii_case("bash") => Ok(Shell::Bash),
+ "POWERSHELL" | _ if s.eq_ignore_ascii_case("powershell") => Ok(Shell::PowerShell),
+ "ELVISH" | _ if s.eq_ignore_ascii_case("elvish") => Ok(Shell::Elvish),
+ _ => Err(String::from("[valid values: bash, fish, zsh, powershell, elvish]")),
+ }
+ }
+}
+
+impl fmt::Display for Shell {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Shell::Bash => write!(f, "BASH"),
+ Shell::Fish => write!(f, "FISH"),
+ Shell::Zsh => write!(f, "ZSH"),
+ Shell::PowerShell => write!(f, "POWERSHELL"),
+ Shell::Elvish => write!(f, "ELVISH"),
+ }
+ }
+}
diff --git a/clap/src/completions/zsh.rs b/clap/src/completions/zsh.rs
new file mode 100644
index 0000000..5d23fd2
--- /dev/null
+++ b/clap/src/completions/zsh.rs
@@ -0,0 +1,472 @@
+// Std
+use std::io::Write;
+#[allow(deprecated, unused_imports)]
+use std::ascii::AsciiExt;
+
+// Internal
+use app::App;
+use app::parser::Parser;
+use args::{AnyArg, ArgSettings};
+use completions;
+use INTERNAL_ERROR_MSG;
+
+pub struct ZshGen<'a, 'b>
+where
+ 'a: 'b,
+{
+ p: &'b Parser<'a, 'b>,
+}
+
+impl<'a, 'b> ZshGen<'a, 'b> {
+ pub fn new(p: &'b Parser<'a, 'b>) -> Self {
+ debugln!("ZshGen::new;");
+ ZshGen { p: p }
+ }
+
+ pub fn generate_to<W: Write>(&self, buf: &mut W) {
+ debugln!("ZshGen::generate_to;");
+ w!(
+ buf,
+ format!(
+ "\
+#compdef {name}
+
+autoload -U is-at-least
+
+_{name}() {{
+ typeset -A opt_args
+ typeset -a _arguments_options
+ local ret=1
+
+ if is-at-least 5.2; then
+ _arguments_options=(-s -S -C)
+ else
+ _arguments_options=(-s -C)
+ fi
+
+ local context curcontext=\"$curcontext\" state line
+ {initial_args}
+ {subcommands}
+}}
+
+{subcommand_details}
+
+_{name} \"$@\"",
+ name = self.p.meta.bin_name.as_ref().unwrap(),
+ initial_args = get_args_of(self.p),
+ subcommands = get_subcommands_of(self.p),
+ subcommand_details = subcommand_details(self.p)
+ ).as_bytes()
+ );
+ }
+}
+
+// Displays the commands of a subcommand
+// (( $+functions[_[bin_name_underscore]_commands] )) ||
+// _[bin_name_underscore]_commands() {
+// local commands; commands=(
+// '[arg_name]:[arg_help]'
+// )
+// _describe -t commands '[bin_name] commands' commands "$@"
+//
+// Where the following variables are present:
+// [bin_name_underscore]: The full space delineated bin_name, where spaces have been replaced by
+// underscore characters
+// [arg_name]: The name of the subcommand
+// [arg_help]: The help message of the subcommand
+// [bin_name]: The full space delineated bin_name
+//
+// Here's a snippet from rustup:
+//
+// (( $+functions[_rustup_commands] )) ||
+// _rustup_commands() {
+// local commands; commands=(
+// 'show:Show the active and installed toolchains'
+// 'update:Update Rust toolchains'
+// # ... snip for brevity
+// 'help:Prints this message or the help of the given subcommand(s)'
+// )
+// _describe -t commands 'rustup commands' commands "$@"
+//
+fn subcommand_details(p: &Parser) -> String {
+ debugln!("ZshGen::subcommand_details;");
+ // First we do ourself
+ let mut ret = vec![
+ format!(
+ "\
+(( $+functions[_{bin_name_underscore}_commands] )) ||
+_{bin_name_underscore}_commands() {{
+ local commands; commands=(
+ {subcommands_and_args}
+ )
+ _describe -t commands '{bin_name} commands' commands \"$@\"
+}}",
+ bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "__"),
+ bin_name = p.meta.bin_name.as_ref().unwrap(),
+ subcommands_and_args = subcommands_of(p)
+ ),
+ ];
+
+ // Next we start looping through all the children, grandchildren, etc.
+ let mut all_subcommands = completions::all_subcommands(p);
+ all_subcommands.sort();
+ all_subcommands.dedup();
+ for &(_, ref bin_name) in &all_subcommands {
+ debugln!("ZshGen::subcommand_details:iter: bin_name={}", bin_name);
+ ret.push(format!(
+ "\
+(( $+functions[_{bin_name_underscore}_commands] )) ||
+_{bin_name_underscore}_commands() {{
+ local commands; commands=(
+ {subcommands_and_args}
+ )
+ _describe -t commands '{bin_name} commands' commands \"$@\"
+}}",
+ bin_name_underscore = bin_name.replace(" ", "__"),
+ bin_name = bin_name,
+ subcommands_and_args = subcommands_of(parser_of(p, bin_name))
+ ));
+ }
+
+ ret.join("\n")
+}
+
+// Generates subcommand completions in form of
+//
+// '[arg_name]:[arg_help]'
+//
+// Where:
+// [arg_name]: the subcommand's name
+// [arg_help]: the help message of the subcommand
+//
+// A snippet from rustup:
+// 'show:Show the active and installed toolchains'
+// 'update:Update Rust toolchains'
+fn subcommands_of(p: &Parser) -> String {
+ debugln!("ZshGen::subcommands_of;");
+ let mut ret = vec![];
+ fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) {
+ debugln!("ZshGen::add_sc;");
+ let s = format!(
+ "\"{name}:{help}\" \\",
+ name = n,
+ help = sc.p
+ .meta
+ .about
+ .unwrap_or("")
+ .replace("[", "\\[")
+ .replace("]", "\\]")
+ );
+ if !s.is_empty() {
+ ret.push(s);
+ }
+ }
+
+ // The subcommands
+ for sc in p.subcommands() {
+ debugln!(
+ "ZshGen::subcommands_of:iter: subcommand={}",
+ sc.p.meta.name
+ );
+ add_sc(sc, &sc.p.meta.name, &mut ret);
+ if let Some(ref v) = sc.p.meta.aliases {
+ for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) {
+ add_sc(sc, alias, &mut ret);
+ }
+ }
+ }
+
+ ret.join("\n")
+}
+
+// Get's the subcommand section of a completion file
+// This looks roughly like:
+//
+// case $state in
+// ([bin_name]_args)
+// curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\"
+// case $line[1] in
+//
+// ([name])
+// _arguments -C -s -S \
+// [subcommand_args]
+// && ret=0
+//
+// [RECURSIVE_CALLS]
+//
+// ;;",
+//
+// [repeat]
+//
+// esac
+// ;;
+// esac",
+//
+// Where the following variables are present:
+// [name] = The subcommand name in the form of "install" for "rustup toolchain install"
+// [bin_name] = The full space delineated bin_name such as "rustup toolchain install"
+// [name_hyphen] = The full space delineated bin_name, but replace spaces with hyphens
+// [repeat] = From the same recursive calls, but for all subcommands
+// [subcommand_args] = The same as zsh::get_args_of
+fn get_subcommands_of(p: &Parser) -> String {
+ debugln!("get_subcommands_of;");
+
+ debugln!(
+ "get_subcommands_of: Has subcommands...{:?}",
+ p.has_subcommands()
+ );
+ if !p.has_subcommands() {
+ return String::new();
+ }
+
+ let sc_names = completions::subcommands_of(p);
+
+ let mut subcmds = vec![];
+ for &(ref name, ref bin_name) in &sc_names {
+ let mut v = vec![format!("({})", name)];
+ let subcommand_args = get_args_of(parser_of(p, &*bin_name));
+ if !subcommand_args.is_empty() {
+ v.push(subcommand_args);
+ }
+ let subcommands = get_subcommands_of(parser_of(p, &*bin_name));
+ if !subcommands.is_empty() {
+ v.push(subcommands);
+ }
+ v.push(String::from(";;"));
+ subcmds.push(v.join("\n"));
+ }
+
+ format!(
+ "case $state in
+ ({name})
+ words=($line[{pos}] \"${{words[@]}}\")
+ (( CURRENT += 1 ))
+ curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$line[{pos}]:\"
+ case $line[{pos}] in
+ {subcommands}
+ esac
+ ;;
+esac",
+ name = p.meta.name,
+ name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"),
+ subcommands = subcmds.join("\n"),
+ pos = p.positionals().len() + 1
+ )
+}
+
+fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> {
+ debugln!("parser_of: sc={}", sc);
+ if sc == p.meta.bin_name.as_ref().unwrap_or(&String::new()) {
+ return p;
+ }
+ &p.find_subcommand(sc).expect(INTERNAL_ERROR_MSG).p
+}
+
+// Writes out the args section, which ends up being the flags, opts and postionals, and a jump to
+// another ZSH function if there are subcommands.
+// The structer works like this:
+// ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)]
+// ^-- list '-v -h' ^--'*' ^--'+' ^-- list 'one two three'
+//
+// An example from the rustup command:
+//
+// _arguments -C -s -S \
+// '(-h --help --verbose)-v[Enable verbose output]' \
+// '(-V -v --version --verbose --help)-h[Prints help information]' \
+// # ... snip for brevity
+// ':: :_rustup_commands' \ # <-- displays subcommands
+// '*::: :->rustup' \ # <-- displays subcommand args and child subcommands
+// && ret=0
+//
+// The args used for _arguments are as follows:
+// -C: modify the $context internal variable
+// -s: Allow stacking of short args (i.e. -a -b -c => -abc)
+// -S: Do not complete anything after '--' and treat those as argument values
+fn get_args_of(p: &Parser) -> String {
+ debugln!("get_args_of;");
+ let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")];
+ let opts = write_opts_of(p);
+ let flags = write_flags_of(p);
+ let positionals = write_positionals_of(p);
+ let sc_or_a = if p.has_subcommands() {
+ format!(
+ "\":: :_{name}_commands\" \\",
+ name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__")
+ )
+ } else {
+ String::new()
+ };
+ let sc = if p.has_subcommands() {
+ format!("\"*::: :->{name}\" \\", name = p.meta.name)
+ } else {
+ String::new()
+ };
+
+ if !opts.is_empty() {
+ ret.push(opts);
+ }
+ if !flags.is_empty() {
+ ret.push(flags);
+ }
+ if !positionals.is_empty() {
+ ret.push(positionals);
+ }
+ if !sc_or_a.is_empty() {
+ ret.push(sc_or_a);
+ }
+ if !sc.is_empty() {
+ ret.push(sc);
+ }
+ ret.push(String::from("&& ret=0"));
+
+ ret.join("\n")
+}
+
+// Escape help string inside single quotes and brackets
+fn escape_help(string: &str) -> String {
+ string
+ .replace("\\", "\\\\")
+ .replace("'", "'\\''")
+ .replace("[", "\\[")
+ .replace("]", "\\]")
+}
+
+// Escape value string inside single quotes and parentheses
+fn escape_value(string: &str) -> String {
+ string
+ .replace("\\", "\\\\")
+ .replace("'", "'\\''")
+ .replace("(", "\\(")
+ .replace(")", "\\)")
+ .replace(" ", "\\ ")
+}
+
+fn write_opts_of(p: &Parser) -> String {
+ debugln!("write_opts_of;");
+ let mut ret = vec![];
+ for o in p.opts() {
+ debugln!("write_opts_of:iter: o={}", o.name());
+ let help = o.help().map_or(String::new(), escape_help);
+ let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG);
+ conflicts = if conflicts.is_empty() {
+ String::new()
+ } else {
+ format!("({})", conflicts)
+ };
+
+ let multiple = if o.is_set(ArgSettings::Multiple) {
+ "*"
+ } else {
+ ""
+ };
+ let pv = if let Some(pv_vec) = o.possible_vals() {
+ format!(": :({})", pv_vec.iter().map(
+ |v| escape_value(*v)).collect::<Vec<String>>().join(" "))
+ } else {
+ String::new()
+ };
+ if let Some(short) = o.short() {
+ let s = format!(
+ "'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\",
+ conflicts = conflicts,
+ multiple = multiple,
+ arg = short,
+ possible_values = pv,
+ help = help
+ );
+
+ debugln!("write_opts_of:iter: Wrote...{}", &*s);
+ ret.push(s);
+ }
+ if let Some(long) = o.long() {
+ let l = format!(
+ "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\",
+ conflicts = conflicts,
+ multiple = multiple,
+ arg = long,
+ possible_values = pv,
+ help = help
+ );
+
+ debugln!("write_opts_of:iter: Wrote...{}", &*l);
+ ret.push(l);
+ }
+ }
+
+ ret.join("\n")
+}
+
+fn write_flags_of(p: &Parser) -> String {
+ debugln!("write_flags_of;");
+ let mut ret = vec![];
+ for f in p.flags() {
+ debugln!("write_flags_of:iter: f={}", f.name());
+ let help = f.help().map_or(String::new(), escape_help);
+ let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG);
+ conflicts = if conflicts.is_empty() {
+ String::new()
+ } else {
+ format!("({})", conflicts)
+ };
+
+ let multiple = if f.is_set(ArgSettings::Multiple) {
+ "*"
+ } else {
+ ""
+ };
+ if let Some(short) = f.short() {
+ let s = format!(
+ "'{conflicts}{multiple}-{arg}[{help}]' \\",
+ multiple = multiple,
+ conflicts = conflicts,
+ arg = short,
+ help = help
+ );
+
+ debugln!("write_flags_of:iter: Wrote...{}", &*s);
+ ret.push(s);
+ }
+
+ if let Some(long) = f.long() {
+ let l = format!(
+ "'{conflicts}{multiple}--{arg}[{help}]' \\",
+ conflicts = conflicts,
+ multiple = multiple,
+ arg = long,
+ help = help
+ );
+
+ debugln!("write_flags_of:iter: Wrote...{}", &*l);
+ ret.push(l);
+ }
+ }
+
+ ret.join("\n")
+}
+
+fn write_positionals_of(p: &Parser) -> String {
+ debugln!("write_positionals_of;");
+ let mut ret = vec![];
+ for arg in p.positionals() {
+ debugln!("write_positionals_of:iter: arg={}", arg.b.name);
+ let a = format!(
+ "'{optional}:{name}{help}:{action}' \\",
+ optional = if !arg.b.is_set(ArgSettings::Required) { ":" } else { "" },
+ name = arg.b.name,
+ help = arg.b
+ .help
+ .map_or("".to_owned(), |v| " -- ".to_owned() + v)
+ .replace("[", "\\[")
+ .replace("]", "\\]"),
+ action = arg.possible_vals().map_or("_files".to_owned(), |values| {
+ format!("({})",
+ values.iter().map(|v| escape_value(*v)).collect::<Vec<String>>().join(" "))
+ })
+ );
+
+ debugln!("write_positionals_of:iter: Wrote...{}", a);
+ ret.push(a);
+ }
+
+ ret.join("\n")
+}
diff --git a/clap/src/errors.rs b/clap/src/errors.rs
new file mode 100644
index 0000000..c6087c0
--- /dev/null
+++ b/clap/src/errors.rs
@@ -0,0 +1,912 @@
+// Std
+use std::convert::From;
+use std::error::Error as StdError;
+use std::fmt as std_fmt;
+use std::fmt::Display;
+use std::io::{self, Write};
+use std::process;
+use std::result::Result as StdResult;
+
+// Internal
+use args::AnyArg;
+use fmt::{ColorWhen, Colorizer, ColorizerOption};
+use suggestions;
+
+/// Short hand for [`Result`] type
+///
+/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
+pub type Result<T> = StdResult<T, Error>;
+
+/// Command line argument parser kind of error
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum ErrorKind {
+ /// Occurs when an [`Arg`] has a set of possible values,
+ /// and the user provides a value which isn't in that set.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .arg(Arg::with_name("speed")
+ /// .possible_value("fast")
+ /// .possible_value("slow"))
+ /// .get_matches_from_safe(vec!["prog", "other"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidValue);
+ /// ```
+ /// [`Arg`]: ./struct.Arg.html
+ InvalidValue,
+
+ /// Occurs when a user provides a flag, option, argument or subcommand which isn't defined.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .arg(Arg::from_usage("--flag 'some flag'"))
+ /// .get_matches_from_safe(vec!["prog", "--other"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnknownArgument);
+ /// ```
+ UnknownArgument,
+
+ /// Occurs when the user provides an unrecognized [`SubCommand`] which meets the threshold for
+ /// being similar enough to an existing subcommand.
+ /// If it doesn't meet the threshold, or the 'suggestions' feature is disabled,
+ /// the more general [`UnknownArgument`] error is returned.
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(feature = "suggestions"), doc = " ```no_run")]
+ #[cfg_attr(feature = "suggestions", doc = " ```")]
+ /// # use clap::{App, Arg, ErrorKind, SubCommand};
+ /// let result = App::new("prog")
+ /// .subcommand(SubCommand::with_name("config")
+ /// .about("Used for configuration")
+ /// .arg(Arg::with_name("config_file")
+ /// .help("The configuration file to use")
+ /// .index(1)))
+ /// .get_matches_from_safe(vec!["prog", "confi"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidSubcommand);
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument
+ InvalidSubcommand,
+
+ /// Occurs when the user provides an unrecognized [`SubCommand`] which either
+ /// doesn't meet the threshold for being similar enough to an existing subcommand,
+ /// or the 'suggestions' feature is disabled.
+ /// Otherwise the more detailed [`InvalidSubcommand`] error is returned.
+ ///
+ /// This error typically happens when passing additional subcommand names to the `help`
+ /// subcommand. Otherwise, the more general [`UnknownArgument`] error is used.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind, SubCommand};
+ /// let result = App::new("prog")
+ /// .subcommand(SubCommand::with_name("config")
+ /// .about("Used for configuration")
+ /// .arg(Arg::with_name("config_file")
+ /// .help("The configuration file to use")
+ /// .index(1)))
+ /// .get_matches_from_safe(vec!["prog", "help", "nothing"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand);
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`InvalidSubcommand`]: ./enum.ErrorKind.html#variant.InvalidSubcommand
+ /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument
+ UnrecognizedSubcommand,
+
+ /// Occurs when the user provides an empty value for an option that does not allow empty
+ /// values.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let res = App::new("prog")
+ /// .arg(Arg::with_name("color")
+ /// .long("color")
+ /// .empty_values(false))
+ /// .get_matches_from_safe(vec!["prog", "--color="]);
+ /// assert!(res.is_err());
+ /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
+ /// ```
+ EmptyValue,
+
+ /// Occurs when the user provides a value for an argument with a custom validation and the
+ /// value fails that validation.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// fn is_numeric(val: String) -> Result<(), String> {
+ /// match val.parse::<i64>() {
+ /// Ok(..) => Ok(()),
+ /// Err(..) => Err(String::from("Value wasn't a number!")),
+ /// }
+ /// }
+ ///
+ /// let result = App::new("prog")
+ /// .arg(Arg::with_name("num")
+ /// .validator(is_numeric))
+ /// .get_matches_from_safe(vec!["prog", "NotANumber"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::ValueValidation);
+ /// ```
+ ValueValidation,
+
+ /// Occurs when a user provides more values for an argument than were defined by setting
+ /// [`Arg::max_values`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .arg(Arg::with_name("arg")
+ /// .multiple(true)
+ /// .max_values(2))
+ /// .get_matches_from_safe(vec!["prog", "too", "many", "values"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooManyValues);
+ /// ```
+ /// [`Arg::max_values`]: ./struct.Arg.html#method.max_values
+ TooManyValues,
+
+ /// Occurs when the user provides fewer values for an argument than were defined by setting
+ /// [`Arg::min_values`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .arg(Arg::with_name("some_opt")
+ /// .long("opt")
+ /// .min_values(3))
+ /// .get_matches_from_safe(vec!["prog", "--opt", "too", "few"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooFewValues);
+ /// ```
+ /// [`Arg::min_values`]: ./struct.Arg.html#method.min_values
+ TooFewValues,
+
+ /// Occurs when the user provides a different number of values for an argument than what's
+ /// been defined by setting [`Arg::number_of_values`] or than was implicitly set by
+ /// [`Arg::value_names`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .arg(Arg::with_name("some_opt")
+ /// .long("opt")
+ /// .takes_value(true)
+ /// .number_of_values(2))
+ /// .get_matches_from_safe(vec!["prog", "--opt", "wrong"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::WrongNumberOfValues);
+ /// ```
+ ///
+ /// [`Arg::number_of_values`]: ./struct.Arg.html#method.number_of_values
+ /// [`Arg::value_names`]: ./struct.Arg.html#method.value_names
+ WrongNumberOfValues,
+
+ /// Occurs when the user provides two values which conflict with each other and can't be used
+ /// together.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .arg(Arg::with_name("debug")
+ /// .long("debug")
+ /// .conflicts_with("color"))
+ /// .arg(Arg::with_name("color")
+ /// .long("color"))
+ /// .get_matches_from_safe(vec!["prog", "--debug", "--color"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::ArgumentConflict);
+ /// ```
+ ArgumentConflict,
+
+ /// Occurs when the user does not provide one or more required arguments.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .arg(Arg::with_name("debug")
+ /// .required(true))
+ /// .get_matches_from_safe(vec!["prog"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+ /// ```
+ MissingRequiredArgument,
+
+ /// Occurs when a subcommand is required (as defined by [`AppSettings::SubcommandRequired`]),
+ /// but the user does not provide one.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, AppSettings, SubCommand, ErrorKind};
+ /// let err = App::new("prog")
+ /// .setting(AppSettings::SubcommandRequired)
+ /// .subcommand(SubCommand::with_name("test"))
+ /// .get_matches_from_safe(vec![
+ /// "myprog",
+ /// ]);
+ /// assert!(err.is_err());
+ /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand);
+ /// # ;
+ /// ```
+ /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired
+ MissingSubcommand,
+
+ /// Occurs when either an argument or [`SubCommand`] is required, as defined by
+ /// [`AppSettings::ArgRequiredElseHelp`], but the user did not provide one.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, AppSettings, ErrorKind, SubCommand};
+ /// let result = App::new("prog")
+ /// .setting(AppSettings::ArgRequiredElseHelp)
+ /// .subcommand(SubCommand::with_name("config")
+ /// .about("Used for configuration")
+ /// .arg(Arg::with_name("config_file")
+ /// .help("The configuration file to use")))
+ /// .get_matches_from_safe(vec!["prog"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingArgumentOrSubcommand);
+ /// ```
+ /// [`SubCommand`]: ./struct.SubCommand.html
+ /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp
+ MissingArgumentOrSubcommand,
+
+ /// Occurs when the user provides multiple values to an argument which doesn't allow that.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .arg(Arg::with_name("debug")
+ /// .long("debug")
+ /// .multiple(false))
+ /// .get_matches_from_safe(vec!["prog", "--debug", "--debug"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnexpectedMultipleUsage);
+ /// ```
+ UnexpectedMultipleUsage,
+
+ /// Occurs when the user provides a value containing invalid UTF-8 for an argument and
+ /// [`AppSettings::StrictUtf8`] is set.
+ ///
+ /// # Platform Specific
+ ///
+ /// Non-Windows platforms only (such as Linux, Unix, macOS, etc.)
+ ///
+ /// # Examples
+ ///
+ #[cfg_attr(not(unix), doc = " ```ignore")]
+ #[cfg_attr(unix, doc = " ```")]
+ /// # use clap::{App, Arg, ErrorKind, AppSettings};
+ /// # use std::os::unix::ffi::OsStringExt;
+ /// # use std::ffi::OsString;
+ /// let result = App::new("prog")
+ /// .setting(AppSettings::StrictUtf8)
+ /// .arg(Arg::with_name("utf8")
+ /// .short("u")
+ /// .takes_value(true))
+ /// .get_matches_from_safe(vec![OsString::from("myprog"),
+ /// OsString::from("-u"),
+ /// OsString::from_vec(vec![0xE9])]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidUtf8);
+ /// ```
+ /// [`AppSettings::StrictUtf8`]: ./enum.AppSettings.html#variant.StrictUtf8
+ InvalidUtf8,
+
+ /// Not a true "error" as it means `--help` or similar was used.
+ /// The help message will be sent to `stdout`.
+ ///
+ /// **Note**: If the help is displayed due to an error (such as missing subcommands) it will
+ /// be sent to `stderr` instead of `stdout`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .get_matches_from_safe(vec!["prog", "--help"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::HelpDisplayed);
+ /// ```
+ HelpDisplayed,
+
+ /// Not a true "error" as it means `--version` or similar was used.
+ /// The message will be sent to `stdout`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use clap::{App, Arg, ErrorKind};
+ /// let result = App::new("prog")
+ /// .get_matches_from_safe(vec!["prog", "--version"]);
+ /// assert!(result.is_err());
+ /// assert_eq!(result.unwrap_err().kind, ErrorKind::VersionDisplayed);
+ /// ```
+ VersionDisplayed,
+
+ /// Occurs when using the [`value_t!`] and [`values_t!`] macros to convert an argument value
+ /// into type `T`, but the argument you requested wasn't used. I.e. you asked for an argument
+ /// with name `config` to be converted, but `config` wasn't used by the user.
+ /// [`value_t!`]: ./macro.value_t!.html
+ /// [`values_t!`]: ./macro.values_t!.html
+ ArgumentNotFound,
+
+ /// Represents an [I/O error].
+ /// Can occur when writing to `stderr` or `stdout` or reading a configuration file.
+ /// [I/O error]: https://doc.rust-lang.org/std/io/struct.Error.html
+ Io,
+
+ /// Represents a [Format error] (which is a part of [`Display`]).
+ /// Typically caused by writing to `stderr` or `stdout`.
+ ///
+ /// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
+ /// [Format error]: https://doc.rust-lang.org/std/fmt/struct.Error.html
+ Format,
+}
+
+/// Command Line Argument Parser Error
+#[derive(Debug)]
+pub struct Error {
+ /// Formatted error message
+ pub message: String,
+ /// The type of error
+ pub kind: ErrorKind,
+ /// Any additional information passed along, such as the argument name that caused the error
+ pub info: Option<Vec<String>>,
+}
+
+impl Error {
+ /// Should the message be written to `stdout` or not
+ pub fn use_stderr(&self) -> bool {
+ match self.kind {
+ ErrorKind::HelpDisplayed | ErrorKind::VersionDisplayed => false,
+ _ => true,
+ }
+ }
+
+ /// Prints the error to `stderr` and exits with a status of `1`
+ pub fn exit(&self) -> ! {
+ if self.use_stderr() {
+ wlnerr!("{}", self.message);
+ process::exit(1);
+ }
+ let out = io::stdout();
+ writeln!(&mut out.lock(), "{}", self.message).expect("Error writing Error to stdout");
+ process::exit(0);
+ }
+
+ #[doc(hidden)]
+ pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) }
+
+ #[doc(hidden)]
+ pub fn argument_conflict<O, U>(
+ arg: &AnyArg,
+ other: Option<O>,
+ usage: U,
+ color: ColorWhen,
+ ) -> Self
+ where
+ O: Into<String>,
+ U: Display,
+ {
+ let mut v = vec![arg.name().to_owned()];
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The argument '{}' cannot be used with {}\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(&*arg.to_string()),
+ match other {
+ Some(name) => {
+ let n = name.into();
+ v.push(n.clone());
+ c.warning(format!("'{}'", n))
+ }
+ None => c.none("one or more of the other specified arguments".to_owned()),
+ },
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::ArgumentConflict,
+ info: Some(v),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn empty_value<U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self
+ where
+ U: Display,
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The argument '{}' requires a value but none was supplied\
+ \n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(arg.to_string()),
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::EmptyValue,
+ info: Some(vec![arg.name().to_owned()]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn invalid_value<B, G, U>(
+ bad_val: B,
+ good_vals: &[G],
+ arg: &AnyArg,
+ usage: U,
+ color: ColorWhen,
+ ) -> Self
+ where
+ B: AsRef<str>,
+ G: AsRef<str> + Display,
+ U: Display,
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ let suffix = suggestions::did_you_mean_value_suffix(bad_val.as_ref(), good_vals.iter());
+
+ let mut sorted = vec![];
+ for v in good_vals {
+ let val = format!("{}", c.good(v));
+ sorted.push(val);
+ }
+ sorted.sort();
+ let valid_values = sorted.join(", ");
+ Error {
+ message: format!(
+ "{} '{}' isn't a valid value for '{}'\n\t\
+ [possible values: {}]\n\
+ {}\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(bad_val.as_ref()),
+ c.warning(arg.to_string()),
+ valid_values,
+ suffix.0,
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::InvalidValue,
+ info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn invalid_subcommand<S, D, N, U>(
+ subcmd: S,
+ did_you_mean: D,
+ name: N,
+ usage: U,
+ color: ColorWhen,
+ ) -> Self
+ where
+ S: Into<String>,
+ D: AsRef<str> + Display,
+ N: Display,
+ U: Display,
+ {
+ let s = subcmd.into();
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The subcommand '{}' wasn't recognized\n\t\
+ Did you mean '{}'?\n\n\
+ If you believe you received this message in error, try \
+ re-running with '{} {} {}'\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(&*s),
+ c.good(did_you_mean.as_ref()),
+ name,
+ c.good("--"),
+ &*s,
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::InvalidSubcommand,
+ info: Some(vec![s]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn unrecognized_subcommand<S, N>(subcmd: S, name: N, color: ColorWhen) -> Self
+ where
+ S: Into<String>,
+ N: Display,
+ {
+ let s = subcmd.into();
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The subcommand '{}' wasn't recognized\n\n\
+ {}\n\t\
+ {} help <subcommands>...\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(&*s),
+ c.warning("USAGE:"),
+ name,
+ c.good("--help")
+ ),
+ kind: ErrorKind::UnrecognizedSubcommand,
+ info: Some(vec![s]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn missing_required_argument<R, U>(required: R, usage: U, color: ColorWhen) -> Self
+ where
+ R: Display,
+ U: Display,
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The following required arguments were not provided:{}\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ required,
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::MissingRequiredArgument,
+ info: None,
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn missing_subcommand<N, U>(name: N, usage: U, color: ColorWhen) -> Self
+ where
+ N: AsRef<str> + Display,
+ U: Display,
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} '{}' requires a subcommand, but one was not provided\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(name),
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::MissingSubcommand,
+ info: None,
+ }
+ }
+
+
+ #[doc(hidden)]
+ pub fn invalid_utf8<U>(usage: U, color: ColorWhen) -> Self
+ where
+ U: Display,
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} Invalid UTF-8 was detected in one or more arguments\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::InvalidUtf8,
+ info: None,
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn too_many_values<V, U>(val: V, arg: &AnyArg, usage: U, color: ColorWhen) -> Self
+ where
+ V: AsRef<str> + Display + ToOwned,
+ U: Display,
+ {
+ let v = val.as_ref();
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The value '{}' was provided to '{}', but it wasn't expecting \
+ any more values\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(v),
+ c.warning(arg.to_string()),
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::TooManyValues,
+ info: Some(vec![arg.name().to_owned(), v.to_owned()]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn too_few_values<U>(
+ arg: &AnyArg,
+ min_vals: u64,
+ curr_vals: usize,
+ usage: U,
+ color: ColorWhen,
+ ) -> Self
+ where
+ U: Display,
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The argument '{}' requires at least {} values, but only {} w{} \
+ provided\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(arg.to_string()),
+ c.warning(min_vals.to_string()),
+ c.warning(curr_vals.to_string()),
+ if curr_vals > 1 { "ere" } else { "as" },
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::TooFewValues,
+ info: Some(vec![arg.name().to_owned()]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn value_validation(arg: Option<&AnyArg>, err: String, color: ColorWhen) -> Self
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} Invalid value{}: {}",
+ c.error("error:"),
+ if let Some(a) = arg {
+ format!(" for '{}'", c.warning(a.to_string()))
+ } else {
+ "".to_string()
+ },
+ err
+ ),
+ kind: ErrorKind::ValueValidation,
+ info: None,
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn value_validation_auto(err: String) -> Self {
+ let n: Option<&AnyArg> = None;
+ Error::value_validation(n, err, ColorWhen::Auto)
+ }
+
+ #[doc(hidden)]
+ pub fn wrong_number_of_values<S, U>(
+ arg: &AnyArg,
+ num_vals: u64,
+ curr_vals: usize,
+ suffix: S,
+ usage: U,
+ color: ColorWhen,
+ ) -> Self
+ where
+ S: Display,
+ U: Display,
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The argument '{}' requires {} values, but {} w{} \
+ provided\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(arg.to_string()),
+ c.warning(num_vals.to_string()),
+ c.warning(curr_vals.to_string()),
+ suffix,
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::WrongNumberOfValues,
+ info: Some(vec![arg.name().to_owned()]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn unexpected_multiple_usage<U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self
+ where
+ U: Display,
+ {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} The argument '{}' was provided more than once, but cannot \
+ be used multiple times\n\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(arg.to_string()),
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::UnexpectedMultipleUsage,
+ info: Some(vec![arg.name().to_owned()]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn unknown_argument<A, U>(arg: A, did_you_mean: &str, usage: U, color: ColorWhen) -> Self
+ where
+ A: Into<String>,
+ U: Display,
+ {
+ let a = arg.into();
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!(
+ "{} Found argument '{}' which wasn't expected, or isn't valid in \
+ this context{}\n\
+ {}\n\n\
+ For more information try {}",
+ c.error("error:"),
+ c.warning(&*a),
+ if did_you_mean.is_empty() {
+ "\n".to_owned()
+ } else {
+ format!("{}\n", did_you_mean)
+ },
+ usage,
+ c.good("--help")
+ ),
+ kind: ErrorKind::UnknownArgument,
+ info: Some(vec![a]),
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn io_error(e: &Error, color: ColorWhen) -> Self {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: color,
+ });
+ Error {
+ message: format!("{} {}", c.error("error:"), e.description()),
+ kind: ErrorKind::Io,
+ info: None,
+ }
+ }
+
+ #[doc(hidden)]
+ pub fn argument_not_found_auto<A>(arg: A) -> Self
+ where
+ A: Into<String>,
+ {
+ let a = arg.into();
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: ColorWhen::Auto,
+ });
+ Error {
+ message: format!(
+ "{} The argument '{}' wasn't found",
+ c.error("error:"),
+ a.clone()
+ ),
+ kind: ErrorKind::ArgumentNotFound,
+ info: Some(vec![a]),
+ }
+ }
+
+ /// Create an error with a custom description.
+ ///
+ /// This can be used in combination with `Error::exit` to exit your program
+ /// with a custom error message.
+ pub fn with_description(description: &str, kind: ErrorKind) -> Self {
+ let c = Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: ColorWhen::Auto,
+ });
+ Error {
+ message: format!("{} {}", c.error("error:"), description),
+ kind: kind,
+ info: None,
+ }
+ }
+}
+
+impl StdError for Error {
+ fn description(&self) -> &str { &*self.message }
+}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut std_fmt::Formatter) -> std_fmt::Result { writeln!(f, "{}", self.message) }
+}
+
+impl From<io::Error> for Error {
+ fn from(e: io::Error) -> Self { Error::with_description(e.description(), ErrorKind::Io) }
+}
+
+impl From<std_fmt::Error> for Error {
+ fn from(e: std_fmt::Error) -> Self {
+ Error::with_description(e.description(), ErrorKind::Format)
+ }
+}
diff --git a/clap/src/fmt.rs b/clap/src/fmt.rs
new file mode 100644
index 0000000..108a635
--- /dev/null
+++ b/clap/src/fmt.rs
@@ -0,0 +1,189 @@
+#[cfg(all(feature = "color", not(target_os = "windows")))]
+use ansi_term::ANSIString;
+
+#[cfg(all(feature = "color", not(target_os = "windows")))]
+use ansi_term::Colour::{Green, Red, Yellow};
+
+#[cfg(feature = "color")]
+use atty;
+use std::fmt;
+use std::env;
+
+#[doc(hidden)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum ColorWhen {
+ Auto,
+ Always,
+ Never,
+}
+
+#[cfg(feature = "color")]
+pub fn is_a_tty(stderr: bool) -> bool {
+ debugln!("is_a_tty: stderr={:?}", stderr);
+ let stream = if stderr {
+ atty::Stream::Stderr
+ } else {
+ atty::Stream::Stdout
+ };
+ atty::is(stream)
+}
+
+#[cfg(not(feature = "color"))]
+pub fn is_a_tty(_: bool) -> bool {
+ debugln!("is_a_tty;");
+ false
+}
+
+pub fn is_term_dumb() -> bool { env::var("TERM").ok() == Some(String::from("dumb")) }
+
+#[doc(hidden)]
+pub struct ColorizerOption {
+ pub use_stderr: bool,
+ pub when: ColorWhen,
+}
+
+#[doc(hidden)]
+pub struct Colorizer {
+ when: ColorWhen,
+}
+
+macro_rules! color {
+ ($_self:ident, $c:ident, $m:expr) => {
+ match $_self.when {
+ ColorWhen::Auto => Format::$c($m),
+ ColorWhen::Always => Format::$c($m),
+ ColorWhen::Never => Format::None($m),
+ }
+ };
+}
+
+impl Colorizer {
+ pub fn new(option: ColorizerOption) -> Colorizer {
+ let is_a_tty = is_a_tty(option.use_stderr);
+ let is_term_dumb = is_term_dumb();
+ Colorizer {
+ when: match option.when {
+ ColorWhen::Auto if is_a_tty && !is_term_dumb => ColorWhen::Auto,
+ ColorWhen::Auto => ColorWhen::Never,
+ when => when,
+ }
+ }
+ }
+
+ pub fn good<T>(&self, msg: T) -> Format<T>
+ where
+ T: fmt::Display + AsRef<str>,
+ {
+ debugln!("Colorizer::good;");
+ color!(self, Good, msg)
+ }
+
+ pub fn warning<T>(&self, msg: T) -> Format<T>
+ where
+ T: fmt::Display + AsRef<str>,
+ {
+ debugln!("Colorizer::warning;");
+ color!(self, Warning, msg)
+ }
+
+ pub fn error<T>(&self, msg: T) -> Format<T>
+ where
+ T: fmt::Display + AsRef<str>,
+ {
+ debugln!("Colorizer::error;");
+ color!(self, Error, msg)
+ }
+
+ pub fn none<T>(&self, msg: T) -> Format<T>
+ where
+ T: fmt::Display + AsRef<str>,
+ {
+ debugln!("Colorizer::none;");
+ Format::None(msg)
+ }
+}
+
+impl Default for Colorizer {
+ fn default() -> Self {
+ Colorizer::new(ColorizerOption {
+ use_stderr: true,
+ when: ColorWhen::Auto,
+ })
+ }
+}
+
+/// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow,
+/// and Good=Green
+#[derive(Debug)]
+#[doc(hidden)]
+pub enum Format<T> {
+ /// Defines the style used for errors, defaults to Red
+ Error(T),
+ /// Defines the style used for warnings, defaults to Yellow
+ Warning(T),
+ /// Defines the style used for good values, defaults to Green
+ Good(T),
+ /// Defines no formatting style
+ None(T),
+}
+
+#[cfg(all(feature = "color", not(target_os = "windows")))]
+impl<T: AsRef<str>> Format<T> {
+ fn format(&self) -> ANSIString {
+ match *self {
+ Format::Error(ref e) => Red.bold().paint(e.as_ref()),
+ Format::Warning(ref e) => Yellow.paint(e.as_ref()),
+ Format::Good(ref e) => Green.paint(e.as_ref()),
+ Format::None(ref e) => ANSIString::from(e.as_ref()),
+ }
+ }
+}
+
+#[cfg(any(not(feature = "color"), target_os = "windows"))]
+#[cfg_attr(feature = "lints", allow(match_same_arms))]
+impl<T: fmt::Display> Format<T> {
+ fn format(&self) -> &T {
+ match *self {
+ Format::Error(ref e) => e,
+ Format::Warning(ref e) => e,
+ Format::Good(ref e) => e,
+ Format::None(ref e) => e,
+ }
+ }
+}
+
+
+#[cfg(all(feature = "color", not(target_os = "windows")))]
+impl<T: AsRef<str>> fmt::Display for Format<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) }
+}
+
+#[cfg(any(not(feature = "color"), target_os = "windows"))]
+impl<T: fmt::Display> fmt::Display for Format<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) }
+}
+
+#[cfg(all(test, feature = "color", not(target_os = "windows")))]
+mod test {
+ use ansi_term::ANSIString;
+ use ansi_term::Colour::{Green, Red, Yellow};
+ use super::Format;
+
+ #[test]
+ fn colored_output() {
+ let err = Format::Error("error");
+ assert_eq!(
+ &*format!("{}", err),
+ &*format!("{}", Red.bold().paint("error"))
+ );
+ let good = Format::Good("good");
+ assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
+ let warn = Format::Warning("warn");
+ assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
+ let none = Format::None("none");
+ assert_eq!(
+ &*format!("{}", none),
+ &*format!("{}", ANSIString::from("none"))
+ );
+ }
+}
diff --git a/clap/src/lib.rs b/clap/src/lib.rs
new file mode 100644
index 0000000..0a3e1bb
--- /dev/null
+++ b/clap/src/lib.rs
@@ -0,0 +1,629 @@
+// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/blob/master/CONTRIBUTORS.md).
+// Licensed under the MIT license
+// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
+// notice may not be copied, modified, or distributed except according to those terms.
+
+//! `clap` is a simple-to-use, efficient, and full-featured library for parsing command line
+//! arguments and subcommands when writing console/terminal applications.
+//!
+//! ## About
+//!
+//! `clap` is used to parse *and validate* the string of command line arguments provided by the user
+//! at runtime. You provide the list of valid possibilities, and `clap` handles the rest. This means
+//! you focus on your *applications* functionality, and less on the parsing and validating of
+//! arguments.
+//!
+//! `clap` also provides the traditional version and help switches (or flags) 'for free' meaning
+//! automatically with no configuration. It does this by checking list of valid possibilities you
+//! supplied and adding only the ones you haven't already defined. If you are using subcommands,
+//! `clap` will also auto-generate a `help` subcommand for you in addition to the traditional flags.
+//!
+//! Once `clap` parses the user provided string of arguments, it returns the matches along with any
+//! applicable values. If the user made an error or typo, `clap` informs them of the mistake and
+//! exits gracefully (or returns a `Result` type and allows you to perform any clean up prior to
+//! exit). Because of this, you can make reasonable assumptions in your code about the validity of
+//! the arguments.
+//!
+//!
+//! ## Quick Example
+//!
+//! The following examples show a quick example of some of the very basic functionality of `clap`.
+//! For more advanced usage, such as requirements, conflicts, groups, multiple values and
+//! occurrences see the [documentation](https://docs.rs/clap/), [examples/] directory of
+//! this repository or the [video tutorials].
+//!
+//! **NOTE:** All of these examples are functionally the same, but show different styles in which to
+//! use `clap`
+//!
+//! The first example shows a method that allows more advanced configuration options (not shown in
+//! this small example), or even dynamically generating arguments when desired. The downside is it's
+//! more verbose.
+//!
+//! ```no_run
+//! // (Full example with detailed comments in examples/01b_quick_example.rs)
+//! //
+//! // This example demonstrates clap's full 'builder pattern' style of creating arguments which is
+//! // more verbose, but allows easier editing, and at times more advanced options, or the possibility
+//! // to generate arguments dynamically.
+//! extern crate clap;
+//! use clap::{Arg, App, SubCommand};
+//!
+//! fn main() {
+//! let matches = App::new("My Super Program")
+//! .version("1.0")
+//! .author("Kevin K. <kbknapp@gmail.com>")
+//! .about("Does awesome things")
+//! .arg(Arg::with_name("config")
+//! .short("c")
+//! .long("config")
+//! .value_name("FILE")
+//! .help("Sets a custom config file")
+//! .takes_value(true))
+//! .arg(Arg::with_name("INPUT")
+//! .help("Sets the input file to use")
+//! .required(true)
+//! .index(1))
+//! .arg(Arg::with_name("v")
+//! .short("v")
+//! .multiple(true)
+//! .help("Sets the level of verbosity"))
+//! .subcommand(SubCommand::with_name("test")
+//! .about("controls testing features")
+//! .version("1.3")
+//! .author("Someone E. <someone_else@other.com>")
+//! .arg(Arg::with_name("debug")
+//! .short("d")
+//! .help("print debug information verbosely")))
+//! .get_matches();
+//!
+//! // Gets a value for config if supplied by user, or defaults to "default.conf"
+//! let config = matches.value_of("config").unwrap_or("default.conf");
+//! println!("Value for config: {}", config);
+//!
+//! // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
+//! // required we could have used an 'if let' to conditionally get the value)
+//! println!("Using input file: {}", matches.value_of("INPUT").unwrap());
+//!
+//! // Vary the output based on how many times the user used the "verbose" flag
+//! // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
+//! match matches.occurrences_of("v") {
+//! 0 => println!("No verbose info"),
+//! 1 => println!("Some verbose info"),
+//! 2 => println!("Tons of verbose info"),
+//! 3 | _ => println!("Don't be crazy"),
+//! }
+//!
+//! // You can handle information about subcommands by requesting their matches by name
+//! // (as below), requesting just the name used, or both at the same time
+//! if let Some(matches) = matches.subcommand_matches("test") {
+//! if matches.is_present("debug") {
+//! println!("Printing debug info...");
+//! } else {
+//! println!("Printing normally...");
+//! }
+//! }
+//!
+//! // more program logic goes here...
+//! }
+//! ```
+//!
+//! The next example shows a far less verbose method, but sacrifices some of the advanced
+//! configuration options (not shown in this small example). This method also takes a *very* minor
+//! runtime penalty.
+//!
+//! ```no_run
+//! // (Full example with detailed comments in examples/01a_quick_example.rs)
+//! //
+//! // This example demonstrates clap's "usage strings" method of creating arguments
+//! // which is less verbose
+//! extern crate clap;
+//! use clap::{Arg, App, SubCommand};
+//!
+//! fn main() {
+//! let matches = App::new("myapp")
+//! .version("1.0")
+//! .author("Kevin K. <kbknapp@gmail.com>")
+//! .about("Does awesome things")
+//! .args_from_usage(
+//! "-c, --config=[FILE] 'Sets a custom config file'
+//! <INPUT> 'Sets the input file to use'
+//! -v... 'Sets the level of verbosity'")
+//! .subcommand(SubCommand::with_name("test")
+//! .about("controls testing features")
+//! .version("1.3")
+//! .author("Someone E. <someone_else@other.com>")
+//! .arg_from_usage("-d, --debug 'Print debug information'"))
+//! .get_matches();
+//!
+//! // Same as previous example...
+//! }
+//! ```
+//!
+//! This third method shows how you can use a YAML file to build your CLI and keep your Rust source
+//! tidy or support multiple localized translations by having different YAML files for each
+//! localization.
+//!
+//! First, create the `cli.yml` file to hold your CLI options, but it could be called anything we
+//! like:
+//!
+//! ```yaml
+//! name: myapp
+//! version: "1.0"
+//! author: Kevin K. <kbknapp@gmail.com>
+//! about: Does awesome things
+//! args:
+//! - config:
+//! short: c
+//! long: config
+//! value_name: FILE
+//! help: Sets a custom config file
+//! takes_value: true
+//! - INPUT:
+//! help: Sets the input file to use
+//! required: true
+//! index: 1
+//! - verbose:
+//! short: v
+//! multiple: true
+//! help: Sets the level of verbosity
+//! subcommands:
+//! - test:
+//! about: controls testing features
+//! version: "1.3"
+//! author: Someone E. <someone_else@other.com>
+//! args:
+//! - debug:
+//! short: d
+//! help: print debug information
+//! ```
+//!
+//! Since this feature requires additional dependencies that not everyone may want, it is *not*
+//! compiled in by default and we need to enable a feature flag in Cargo.toml:
+//!
+//! Simply change your `clap = "~2.27.0"` to `clap = {version = "~2.27.0", features = ["yaml"]}`.
+//!
+//! At last we create our `main.rs` file just like we would have with the previous two examples:
+//!
+//! ```ignore
+//! // (Full example with detailed comments in examples/17_yaml.rs)
+//! //
+//! // This example demonstrates clap's building from YAML style of creating arguments which is far
+//! // more clean, but takes a very small performance hit compared to the other two methods.
+//! #[macro_use]
+//! extern crate clap;
+//! use clap::App;
+//!
+//! fn main() {
+//! // The YAML file is found relative to the current file, similar to how modules are found
+//! let yaml = load_yaml!("cli.yml");
+//! let matches = App::from_yaml(yaml).get_matches();
+//!
+//! // Same as previous examples...
+//! }
+//! ```
+//!
+//! Finally there is a macro version, which is like a hybrid approach offering the speed of the
+//! builder pattern (the first example), but without all the verbosity.
+//!
+//! ```no_run
+//! #[macro_use]
+//! extern crate clap;
+//!
+//! fn main() {
+//! let matches = clap_app!(myapp =>
+//! (version: "1.0")
+//! (author: "Kevin K. <kbknapp@gmail.com>")
+//! (about: "Does awesome things")
+//! (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
+//! (@arg INPUT: +required "Sets the input file to use")
+//! (@arg debug: -d ... "Sets the level of debugging information")
+//! (@subcommand test =>
+//! (about: "controls testing features")
+//! (version: "1.3")
+//! (author: "Someone E. <someone_else@other.com>")
+//! (@arg verbose: -v --verbose "Print test information verbosely")
+//! )
+//! ).get_matches();
+//!
+//! // Same as before...
+//! }
+//! ```
+//!
+//! If you were to compile any of the above programs and run them with the flag `--help` or `-h` (or
+//! `help` subcommand, since we defined `test` as a subcommand) the following would be output
+//!
+//! ```text
+//! $ myprog --help
+//! My Super Program 1.0
+//! Kevin K. <kbknapp@gmail.com>
+//! Does awesome things
+//!
+//! USAGE:
+//! MyApp [FLAGS] [OPTIONS] <INPUT> [SUBCOMMAND]
+//!
+//! FLAGS:
+//! -h, --help Prints this message
+//! -v Sets the level of verbosity
+//! -V, --version Prints version information
+//!
+//! OPTIONS:
+//! -c, --config <FILE> Sets a custom config file
+//!
+//! ARGS:
+//! INPUT The input file to use
+//!
+//! SUBCOMMANDS:
+//! help Prints this message
+//! test Controls testing features
+//! ```
+//!
+//! **NOTE:** You could also run `myapp test --help` to see similar output and options for the
+//! `test` subcommand.
+//!
+//! ## Try it!
+//!
+//! ### Pre-Built Test
+//!
+//! To try out the pre-built example, use the following steps:
+//!
+//! * Clone the repository `$ git clone https://github.com/clap-rs/clap && cd clap-rs/tests`
+//! * Compile the example `$ cargo build --release`
+//! * Run the help info `$ ./target/release/claptests --help`
+//! * Play with the arguments!
+//!
+//! ### BYOB (Build Your Own Binary)
+//!
+//! To test out `clap`'s default auto-generated help/version follow these steps:
+//!
+//! * Create a new cargo project `$ cargo new fake --bin && cd fake`
+//! * Add `clap` to your `Cargo.toml`
+//!
+//! ```toml
+//! [dependencies]
+//! clap = "2"
+//! ```
+//!
+//! * Add the following to your `src/main.rs`
+//!
+//! ```no_run
+//! extern crate clap;
+//! use clap::App;
+//!
+//! fn main() {
+//! App::new("fake").version("v1.0-beta").get_matches();
+//! }
+//! ```
+//!
+//! * Build your program `$ cargo build --release`
+//! * Run with help or version `$ ./target/release/fake --help` or `$ ./target/release/fake
+//! --version`
+//!
+//! ## Usage
+//!
+//! For full usage, add `clap` as a dependency in your `Cargo.toml` (it is **highly** recommended to
+//! use the `~major.minor.patch` style versions in your `Cargo.toml`, for more information see
+//! [Compatibility Policy](#compatibility-policy)) to use from crates.io:
+//!
+//! ```toml
+//! [dependencies]
+//! clap = "~2.27.0"
+//! ```
+//!
+//! Or get the latest changes from the master branch at github:
+//!
+//! ```toml
+//! [dependencies.clap]
+//! git = "https://github.com/clap-rs/clap.git"
+//! ```
+//!
+//! Add `extern crate clap;` to your crate root.
+//!
+//! Define a list of valid arguments for your program (see the
+//! [documentation](https://docs.rs/clap/) or [examples/] directory of this repo)
+//!
+//! Then run `cargo build` or `cargo update && cargo build` for your project.
+//!
+//! ### Optional Dependencies / Features
+//!
+//! #### Features enabled by default
+//!
+//! * `suggestions`: Turns on the `Did you mean '--myoption'?` feature for when users make typos. (builds dependency `strsim`)
+//! * `color`: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` and `atty`)
+//! * `wrap_help`: Wraps the help at the actual terminal width when
+//! available, instead of 120 characters. (builds dependency `textwrap`
+//! with feature `term_size`)
+//!
+//! To disable these, add this to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies.clap]
+//! version = "~2.27.0"
+//! default-features = false
+//! ```
+//!
+//! You can also selectively enable only the features you'd like to include, by adding:
+//!
+//! ```toml
+//! [dependencies.clap]
+//! version = "~2.27.0"
+//! default-features = false
+//!
+//! # Cherry-pick the features you'd like to use
+//! features = [ "suggestions", "color" ]
+//! ```
+//!
+//! #### Opt-in features
+//!
+//! * **"yaml"**: Enables building CLIs from YAML documents. (builds dependency `yaml-rust`)
+//! * **"unstable"**: Enables unstable `clap` features that may change from release to release
+//!
+//! ### Dependencies Tree
+//!
+//! The following graphic depicts `clap`s dependency graph (generated using
+//! [cargo-graph](https://github.com/kbknapp/cargo-graph)).
+//!
+//! * **Dashed** Line: Optional dependency
+//! * **Red** Color: **NOT** included by default (must use cargo `features` to enable)
+//! * **Blue** Color: Dev dependency, only used while developing.
+//!
+//! ![clap dependencies](https://raw.githubusercontent.com/clap-rs/clap/master/clap_dep_graph.png)
+//!
+//! ### More Information
+//!
+//! You can find complete documentation on the [docs.rs](https://docs.rs/clap/) for this project.
+//!
+//! You can also find usage examples in the [examples/] directory of this repo.
+//!
+//! #### Video Tutorials
+//!
+//! There's also the video tutorial series [Argument Parsing with Rust v2][video tutorials].
+//!
+//! These videos slowly trickle out as I finish them and currently a work in progress.
+//!
+//! ## How to Contribute
+//!
+//! Contributions are always welcome! And there is a multitude of ways in which you can help
+//! depending on what you like to do, or are good at. Anything from documentation, code cleanup,
+//! issue completion, new features, you name it, even filing issues is contributing and greatly
+//! appreciated!
+//!
+//! Another really great way to help is if you find an interesting, or helpful way in which to use
+//! `clap`. You can either add it to the [examples/] directory, or file an issue and tell
+//! me. I'm all about giving credit where credit is due :)
+//!
+//! Please read [CONTRIBUTING.md](https://raw.githubusercontent.com/clap-rs/clap/master/.github/CONTRIBUTING.md) before you start contributing.
+//!
+//!
+//! ### Testing Code
+//!
+//! To test with all features both enabled and disabled, you can run theese commands:
+//!
+//! ```text
+//! $ cargo test --no-default-features
+//! $ cargo test --features "yaml unstable"
+//! ```
+//!
+//! Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the
+//! prebuilt recipes. *Not* using `just` is perfectly fine as well, it simply bundles commands
+//! automatically.
+//!
+//! For example, to test the code, as above simply run:
+//!
+//! ```text
+//! $ just run-tests
+//! ```
+//!
+//! From here on, I will list the appropriate `cargo` command as well as the `just` command.
+//!
+//! Sometimes it's helpful to only run a subset of the tests, which can be done via:
+//!
+//! ```text
+//! $ cargo test --test <test_name>
+//!
+//! # Or
+//!
+//! $ just run-test <test_name>
+//! ```
+//!
+//! ### Linting Code
+//!
+//! During the CI process `clap` runs against many different lints using
+//! [`clippy`](https://github.com/Manishearth/rust-clippy). In order to check if these lints pass on
+//! your own computer prior to submitting a PR you'll need a nightly compiler.
+//!
+//! In order to check the code for lints run either:
+//!
+//! ```text
+//! $ rustup override add nightly
+//! $ cargo build --features lints
+//! $ rustup override remove
+//!
+//! # Or
+//!
+//! $ just lint
+//! ```
+//!
+//! ### Debugging Code
+//!
+//! Another helpful technique is to see the `clap` debug output while developing features. In order
+//! to see the debug output while running the full test suite or individual tests, run:
+//!
+//! ```text
+//! $ cargo test --features debug
+//!
+//! # Or for individual tests
+//! $ cargo test --test <test_name> --features debug
+//!
+//! # The corresponding just command for individual debugging tests is:
+//! $ just debug <test_name>
+//! ```
+//!
+//! ### Goals
+//!
+//! There are a few goals of `clap` that I'd like to maintain throughout contributions. If your
+//! proposed changes break, or go against any of these goals we'll discuss the changes further
+//! before merging (but will *not* be ignored, all contributes are welcome!). These are by no means
+//! hard-and-fast rules, as I'm no expert and break them myself from time to time (even if by
+//! mistake or ignorance).
+//!
+//! * Remain backwards compatible when possible
+//! - If backwards compatibility *must* be broken, use deprecation warnings if at all possible before
+//! removing legacy code - This does not apply for security concerns
+//! * Parse arguments quickly
+//! - Parsing of arguments shouldn't slow down usage of the main program - This is also true of
+//! generating help and usage information (although *slightly* less stringent, as the program is about
+//! to exit)
+//! * Try to be cognizant of memory usage
+//! - Once parsing is complete, the memory footprint of `clap` should be low since the main program
+//! is the star of the show
+//! * `panic!` on *developer* error, exit gracefully on *end-user* error
+//!
+//! ### Compatibility Policy
+//!
+//! Because `clap` takes `SemVer` and compatibility seriously, this is the official policy regarding
+//! breaking changes and previous versions of Rust.
+//!
+//! `clap` will pin the minimum required version of Rust to the CI builds. Bumping the minimum
+//! version of Rust is considered a minor breaking change, meaning *at a minimum* the minor version
+//! of `clap` will be bumped.
+//!
+//! In order to keep from being surprised by breaking changes, it is **highly** recommended to use
+//! the `~major.minor.patch` style in your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies] clap = "~2.27.0"
+//! ```
+//!
+//! This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore
+//! cannot break due to new features, or bumped minimum versions of Rust.
+//!
+//! #### Minimum Version of Rust
+//!
+//! `clap` will officially support current stable Rust, minus two releases, but may work with prior
+//! releases as well. For example, current stable Rust at the time of this writing is 1.21.0,
+//! meaning `clap` is guaranteed to compile with 1.19.0 and beyond. At the 1.22.0 release, `clap`
+//! will be guaranteed to compile with 1.20.0 and beyond, etc.
+//!
+//! Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be
+//! clearly annotated in the `CHANGELOG.md`
+//!
+//! ## License
+//!
+//! `clap` is licensed under the MIT license. Please read the [LICENSE-MIT][license] file in
+//! this repository for more information.
+//!
+//! [examples/]: https://github.com/clap-rs/clap/tree/master/examples
+//! [video tutorials]: https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U
+//! [license]: https://raw.githubusercontent.com/clap-rs/clap/master/LICENSE-MIT
+
+#![crate_type = "lib"]
+#![doc(html_root_url = "https://docs.rs/clap/2.33.0")]
+#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
+ unused_import_braces, unused_allocation)]
+// Lints we'd like to deny but are currently failing for upstream crates
+// unused_qualifications (bitflags, clippy)
+// trivial_numeric_casts (bitflags)
+#![cfg_attr(not(any(feature = "lints", feature = "nightly")), forbid(unstable_features))]
+#![cfg_attr(feature = "lints", feature(plugin))]
+#![cfg_attr(feature = "lints", plugin(clippy))]
+// Need to disable deny(warnings) while deprecations are active
+// #![cfg_attr(feature = "lints", deny(warnings))]
+#![cfg_attr(feature = "lints", allow(cyclomatic_complexity))]
+#![cfg_attr(feature = "lints", allow(doc_markdown))]
+#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
+
+#[cfg(all(feature = "color", not(target_os = "windows")))]
+extern crate ansi_term;
+#[cfg(feature = "color")]
+extern crate atty;
+#[macro_use]
+extern crate bitflags;
+#[cfg(feature = "suggestions")]
+extern crate strsim;
+#[cfg(feature = "wrap_help")]
+extern crate term_size;
+extern crate textwrap;
+extern crate unicode_width;
+#[cfg(feature = "vec_map")]
+extern crate vec_map;
+#[cfg(feature = "yaml")]
+extern crate yaml_rust;
+
+#[cfg(feature = "yaml")]
+pub use yaml_rust::YamlLoader;
+pub use args::{Arg, ArgGroup, ArgMatches, ArgSettings, OsValues, SubCommand, Values};
+pub use app::{App, AppSettings};
+pub use fmt::Format;
+pub use errors::{Error, ErrorKind, Result};
+pub use completions::Shell;
+
+#[macro_use]
+mod macros;
+mod app;
+mod args;
+mod usage_parser;
+mod fmt;
+mod suggestions;
+mod errors;
+mod osstringext;
+mod strext;
+mod completions;
+mod map;
+
+const INTERNAL_ERROR_MSG: &'static str = "Fatal internal error. Please consider filing a bug \
+ report at https://github.com/clap-rs/clap/issues";
+const INVALID_UTF8: &'static str = "unexpected invalid UTF-8 code point";
+
+#[cfg(unstable)]
+pub use derive::{ArgEnum, ClapApp, FromArgMatches, IntoApp};
+
+#[cfg(unstable)]
+mod derive {
+ /// @TODO @release @docs
+ pub trait ClapApp: IntoApp + FromArgMatches + Sized {
+ /// @TODO @release @docs
+ fn parse() -> Self { Self::from_argmatches(Self::into_app().get_matches()) }
+
+ /// @TODO @release @docs
+ fn parse_from<I, T>(argv: I) -> Self
+ where
+ I: IntoIterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ Self::from_argmatches(Self::into_app().get_matches_from(argv))
+ }
+
+ /// @TODO @release @docs
+ fn try_parse() -> Result<Self, clap::Error> {
+ Self::try_from_argmatches(Self::into_app().get_matches_safe()?)
+ }
+
+
+ /// @TODO @release @docs
+ fn try_parse_from<I, T>(argv: I) -> Result<Self, clap::Error>
+ where
+ I: IntoIterator<Item = T>,
+ T: Into<OsString> + Clone,
+ {
+ Self::try_from_argmatches(Self::into_app().get_matches_from_safe(argv)?)
+ }
+ }
+
+ /// @TODO @release @docs
+ pub trait IntoApp {
+ /// @TODO @release @docs
+ fn into_app<'a, 'b>() -> clap::App<'a, 'b>;
+ }
+
+ /// @TODO @release @docs
+ pub trait FromArgMatches: Sized {
+ /// @TODO @release @docs
+ fn from_argmatches<'a>(matches: clap::ArgMatches<'a>) -> Self;
+
+ /// @TODO @release @docs
+ fn try_from_argmatches<'a>(matches: clap::ArgMatches<'a>) -> Result<Self, clap::Error>;
+ }
+
+ /// @TODO @release @docs
+ pub trait ArgEnum {}
+}
diff --git a/clap/src/macros.rs b/clap/src/macros.rs
new file mode 100644
index 0000000..8198e19
--- /dev/null
+++ b/clap/src/macros.rs
@@ -0,0 +1,1108 @@
+/// A convenience macro for loading the YAML file at compile time (relative to the current file,
+/// like modules work). That YAML object can then be passed to this function.
+///
+/// # Panics
+///
+/// The YAML file must be properly formatted or this function will panic!(). A good way to
+/// ensure this doesn't happen is to run your program with the `--help` switch. If this passes
+/// without error, you needn't worry because the YAML is properly formatted.
+///
+/// # Examples
+///
+/// The following example shows how to load a properly formatted YAML file to build an instance
+/// of an `App` struct.
+///
+/// ```ignore
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let yml = load_yaml!("app.yml");
+/// let app = App::from_yaml(yml);
+///
+/// // continued logic goes here, such as `app.get_matches()` etc.
+/// # }
+/// ```
+#[cfg(feature = "yaml")]
+#[macro_export]
+macro_rules! load_yaml {
+ ($yml:expr) => (
+ &::clap::YamlLoader::load_from_str(include_str!($yml)).expect("failed to load YAML file")[0]
+ );
+}
+
+/// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] from an
+/// argument value. This macro returns a `Result<T,String>` which allows you as the developer to
+/// decide what you'd like to do on a failed parse. There are two types of errors, parse failures
+/// and those where the argument wasn't present (such as a non-required argument). You can use
+/// it to get a single value, or a iterator as with the [`ArgMatches::values_of`]
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let matches = App::new("myapp")
+/// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'")
+/// .get_matches();
+///
+/// let len = value_t!(matches.value_of("length"), u32).unwrap_or_else(|e| e.exit());
+/// let also_len = value_t!(matches, "length", u32).unwrap_or_else(|e| e.exit());
+///
+/// println!("{} + 2: {}", len, len + 2);
+/// # }
+/// ```
+/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
+/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of
+/// [`Result<T,String>`]: https://doc.rust-lang.org/std/result/enum.Result.html
+#[macro_export]
+macro_rules! value_t {
+ ($m:ident, $v:expr, $t:ty) => {
+ value_t!($m.value_of($v), $t)
+ };
+ ($m:ident.value_of($v:expr), $t:ty) => {
+ if let Some(v) = $m.value_of($v) {
+ match v.parse::<$t>() {
+ Ok(val) => Ok(val),
+ Err(_) =>
+ Err(::clap::Error::value_validation_auto(
+ format!("The argument '{}' isn't a valid value", v))),
+ }
+ } else {
+ Err(::clap::Error::argument_not_found_auto($v))
+ }
+ };
+}
+
+/// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] or
+/// exiting upon error, instead of returning a [`Result`] type.
+///
+/// **NOTE:** This macro is for backwards compatibility sake. Prefer
+/// [`value_t!(/* ... */).unwrap_or_else(|e| e.exit())`]
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let matches = App::new("myapp")
+/// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'")
+/// .get_matches();
+///
+/// let len = value_t_or_exit!(matches.value_of("length"), u32);
+/// let also_len = value_t_or_exit!(matches, "length", u32);
+///
+/// println!("{} + 2: {}", len, len + 2);
+/// # }
+/// ```
+/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
+/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
+/// [`value_t!(/* ... */).unwrap_or_else(|e| e.exit())`]: ./macro.value_t!.html
+#[macro_export]
+macro_rules! value_t_or_exit {
+ ($m:ident, $v:expr, $t:ty) => {
+ value_t_or_exit!($m.value_of($v), $t)
+ };
+ ($m:ident.value_of($v:expr), $t:ty) => {
+ if let Some(v) = $m.value_of($v) {
+ match v.parse::<$t>() {
+ Ok(val) => val,
+ Err(_) =>
+ ::clap::Error::value_validation_auto(
+ format!("The argument '{}' isn't a valid value", v)).exit(),
+ }
+ } else {
+ ::clap::Error::argument_not_found_auto($v).exit()
+ }
+ };
+}
+
+/// Convenience macro getting a typed value [`Vec<T>`] where `T` implements [`std::str::FromStr`]
+/// This macro returns a [`clap::Result<Vec<T>>`] which allows you as the developer to decide
+/// what you'd like to do on a failed parse.
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let matches = App::new("myapp")
+/// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'")
+/// .get_matches();
+///
+/// let vals = values_t!(matches.values_of("seq"), u32).unwrap_or_else(|e| e.exit());
+/// for v in &vals {
+/// println!("{} + 2: {}", v, v + 2);
+/// }
+///
+/// let vals = values_t!(matches, "seq", u32).unwrap_or_else(|e| e.exit());
+/// for v in &vals {
+/// println!("{} + 2: {}", v, v + 2);
+/// }
+/// # }
+/// ```
+/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
+/// [`Vec<T>`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
+/// [`clap::Result<Vec<T>>`]: ./type.Result.html
+#[macro_export]
+macro_rules! values_t {
+ ($m:ident, $v:expr, $t:ty) => {
+ values_t!($m.values_of($v), $t)
+ };
+ ($m:ident.values_of($v:expr), $t:ty) => {
+ if let Some(vals) = $m.values_of($v) {
+ let mut tmp = vec![];
+ let mut err = None;
+ for pv in vals {
+ match pv.parse::<$t>() {
+ Ok(rv) => tmp.push(rv),
+ Err(..) => {
+ err = Some(::clap::Error::value_validation_auto(
+ format!("The argument '{}' isn't a valid value", pv)));
+ break
+ }
+ }
+ }
+ match err {
+ Some(e) => Err(e),
+ None => Ok(tmp),
+ }
+ } else {
+ Err(::clap::Error::argument_not_found_auto($v))
+ }
+ };
+}
+
+/// Convenience macro getting a typed value [`Vec<T>`] where `T` implements [`std::str::FromStr`]
+/// or exiting upon error.
+///
+/// **NOTE:** This macro is for backwards compatibility sake. Prefer
+/// [`values_t!(/* ... */).unwrap_or_else(|e| e.exit())`]
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let matches = App::new("myapp")
+/// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'")
+/// .get_matches();
+///
+/// let vals = values_t_or_exit!(matches.values_of("seq"), u32);
+/// for v in &vals {
+/// println!("{} + 2: {}", v, v + 2);
+/// }
+///
+/// // type for example only
+/// let vals: Vec<u32> = values_t_or_exit!(matches, "seq", u32);
+/// for v in &vals {
+/// println!("{} + 2: {}", v, v + 2);
+/// }
+/// # }
+/// ```
+/// [`values_t!(/* ... */).unwrap_or_else(|e| e.exit())`]: ./macro.values_t!.html
+/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
+/// [`Vec<T>`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
+#[macro_export]
+macro_rules! values_t_or_exit {
+ ($m:ident, $v:expr, $t:ty) => {
+ values_t_or_exit!($m.values_of($v), $t)
+ };
+ ($m:ident.values_of($v:expr), $t:ty) => {
+ if let Some(vals) = $m.values_of($v) {
+ vals.map(|v| v.parse::<$t>().unwrap_or_else(|_|{
+ ::clap::Error::value_validation_auto(
+ format!("One or more arguments aren't valid values")).exit()
+ })).collect::<Vec<$t>>()
+ } else {
+ ::clap::Error::argument_not_found_auto($v).exit()
+ }
+ };
+}
+
+// _clap_count_exprs! is derived from https://github.com/DanielKeep/rust-grabbag
+// commit: 82a35ca5d9a04c3b920622d542104e3310ee5b07
+// License: MIT
+// Copyright ⓒ 2015 grabbag contributors.
+// Licensed under the MIT license (see LICENSE or <http://opensource.org
+// /licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
+// <http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
+// files in the project carrying such notice may not be copied, modified,
+// or distributed except according to those terms.
+//
+/// Counts the number of comma-delimited expressions passed to it. The result is a compile-time
+/// evaluable expression, suitable for use as a static array size, or the value of a `const`.
+///
+/// # Examples
+///
+/// ```
+/// # #[macro_use] extern crate clap;
+/// # fn main() {
+/// const COUNT: usize = _clap_count_exprs!(a, 5+1, "hi there!".into_string());
+/// assert_eq!(COUNT, 3);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! _clap_count_exprs {
+ () => { 0 };
+ ($e:expr) => { 1 };
+ ($e:expr, $($es:expr),+) => { 1 + $crate::_clap_count_exprs!($($es),*) };
+}
+
+/// Convenience macro to generate more complete enums with variants to be used as a type when
+/// parsing arguments. This enum also provides a `variants()` function which can be used to
+/// retrieve a `Vec<&'static str>` of the variant names, as well as implementing [`FromStr`] and
+/// [`Display`] automatically.
+///
+/// **NOTE:** Case insensitivity is supported for ASCII characters only. It's highly recommended to
+/// use [`Arg::case_insensitive(true)`] for args that will be used with these enums
+///
+/// **NOTE:** This macro automatically implements [`std::str::FromStr`] and [`std::fmt::Display`]
+///
+/// **NOTE:** These enums support pub (or not) and uses of the `#[derive()]` traits
+///
+/// # Examples
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::{App, Arg};
+/// arg_enum!{
+/// #[derive(PartialEq, Debug)]
+/// pub enum Foo {
+/// Bar,
+/// Baz,
+/// Qux
+/// }
+/// }
+/// // Foo enum can now be used via Foo::Bar, or Foo::Baz, etc
+/// // and implements std::str::FromStr to use with the value_t! macros
+/// fn main() {
+/// let m = App::new("app")
+/// .arg(Arg::from_usage("<foo> 'the foo'")
+/// .possible_values(&Foo::variants())
+/// .case_insensitive(true))
+/// .get_matches_from(vec![
+/// "app", "baz"
+/// ]);
+/// let f = value_t!(m, "foo", Foo).unwrap_or_else(|e| e.exit());
+///
+/// assert_eq!(f, Foo::Baz);
+/// }
+/// ```
+/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
+/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
+/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
+/// [`std::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
+/// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.case_insensitive
+#[macro_export]
+macro_rules! arg_enum {
+ (@as_item $($i:item)*) => ($($i)*);
+ (@impls ( $($tts:tt)* ) -> ($e:ident, $($v:ident),+)) => {
+ arg_enum!(@as_item
+ $($tts)*
+
+ impl ::std::str::FromStr for $e {
+ type Err = String;
+
+ fn from_str(s: &str) -> ::std::result::Result<Self,Self::Err> {
+ #[allow(deprecated, unused_imports)]
+ use ::std::ascii::AsciiExt;
+ match s {
+ $(stringify!($v) |
+ _ if s.eq_ignore_ascii_case(stringify!($v)) => Ok($e::$v)),+,
+ _ => Err({
+ let v = vec![
+ $(stringify!($v),)+
+ ];
+ format!("valid values: {}",
+ v.join(", "))
+ }),
+ }
+ }
+ }
+ impl ::std::fmt::Display for $e {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ match *self {
+ $($e::$v => write!(f, stringify!($v)),)+
+ }
+ }
+ }
+ impl $e {
+ #[allow(dead_code)]
+ pub fn variants() -> [&'static str; $crate::_clap_count_exprs!($(stringify!($v)),+)] {
+ [
+ $(stringify!($v),)+
+ ]
+ }
+ });
+ };
+ ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
+ arg_enum!(@impls
+ ($(#[$($m),+])+
+ pub enum $e {
+ $($v$(=$val)*),+
+ }) -> ($e, $($v),+)
+ );
+ };
+ ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
+ arg_enum!(@impls
+ ($(#[$($m),+])+
+ pub enum $e {
+ $($v$(=$val)*),+
+ }) -> ($e, $($v),+)
+ );
+ };
+ ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
+ arg_enum!(@impls
+ ($(#[$($m),+])+
+ enum $e {
+ $($v$(=$val)*),+
+ }) -> ($e, $($v),+)
+ );
+ };
+ ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
+ arg_enum!(@impls
+ ($(#[$($m),+])+
+ enum $e {
+ $($v$(=$val)*),+
+ }) -> ($e, $($v),+)
+ );
+ };
+ (pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
+ arg_enum!(@impls
+ (pub enum $e {
+ $($v$(=$val)*),+
+ }) -> ($e, $($v),+)
+ );
+ };
+ (pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
+ arg_enum!(@impls
+ (pub enum $e {
+ $($v$(=$val)*),+
+ }) -> ($e, $($v),+)
+ );
+ };
+ (enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => {
+ arg_enum!(@impls
+ (enum $e {
+ $($v$(=$val)*),+
+ }) -> ($e, $($v),+)
+ );
+ };
+ (enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => {
+ arg_enum!(@impls
+ (enum $e {
+ $($v$(=$val)*),+
+ }) -> ($e, $($v),+)
+ );
+ };
+}
+
+/// Allows you to pull the version from your Cargo.toml at compile time as
+/// `MAJOR.MINOR.PATCH_PKGVERSION_PRE`
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let m = App::new("app")
+/// .version(crate_version!())
+/// .get_matches();
+/// # }
+/// ```
+#[cfg(not(feature = "no_cargo"))]
+#[macro_export]
+macro_rules! crate_version {
+ () => {
+ env!("CARGO_PKG_VERSION")
+ };
+}
+
+/// Allows you to pull the authors for the app from your Cargo.toml at
+/// compile time in the form:
+/// `"author1 lastname <author1@example.com>:author2 lastname <author2@example.com>"`
+///
+/// You can replace the colons with a custom separator by supplying a
+/// replacement string, so, for example,
+/// `crate_authors!(",\n")` would become
+/// `"author1 lastname <author1@example.com>,\nauthor2 lastname <author2@example.com>,\nauthor3 lastname <author3@example.com>"`
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let m = App::new("app")
+/// .author(crate_authors!("\n"))
+/// .get_matches();
+/// # }
+/// ```
+#[cfg(not(feature = "no_cargo"))]
+#[macro_export]
+macro_rules! crate_authors {
+ ($sep:expr) => {{
+ use std::ops::Deref;
+ use std::sync::{ONCE_INIT, Once};
+
+ #[allow(missing_copy_implementations)]
+ #[allow(dead_code)]
+ struct CargoAuthors { __private_field: () };
+
+ impl Deref for CargoAuthors {
+ type Target = str;
+
+ #[allow(unsafe_code)]
+ fn deref(&self) -> &'static str {
+ static ONCE: Once = ONCE_INIT;
+ static mut VALUE: *const String = 0 as *const String;
+
+ unsafe {
+ ONCE.call_once(|| {
+ let s = env!("CARGO_PKG_AUTHORS").replace(':', $sep);
+ VALUE = Box::into_raw(Box::new(s));
+ });
+
+ &(*VALUE)[..]
+ }
+ }
+ }
+
+ &*CargoAuthors { __private_field: () }
+ }};
+ () => {
+ env!("CARGO_PKG_AUTHORS")
+ };
+}
+
+/// Allows you to pull the description from your Cargo.toml at compile time.
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let m = App::new("app")
+/// .about(crate_description!())
+/// .get_matches();
+/// # }
+/// ```
+#[cfg(not(feature = "no_cargo"))]
+#[macro_export]
+macro_rules! crate_description {
+ () => {
+ env!("CARGO_PKG_DESCRIPTION")
+ };
+}
+
+/// Allows you to pull the name from your Cargo.toml at compile time.
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # use clap::App;
+/// # fn main() {
+/// let m = App::new(crate_name!())
+/// .get_matches();
+/// # }
+/// ```
+#[cfg(not(feature = "no_cargo"))]
+#[macro_export]
+macro_rules! crate_name {
+ () => {
+ env!("CARGO_PKG_NAME")
+ };
+}
+
+/// Allows you to build the `App` instance from your Cargo.toml at compile time.
+///
+/// Equivalent to using the `crate_*!` macros with their respective fields.
+///
+/// Provided separator is for the [`crate_authors!`](macro.crate_authors.html) macro,
+/// refer to the documentation therefor.
+///
+/// **NOTE:** Changing the values in your `Cargo.toml` does not trigger a re-build automatically,
+/// and therefore won't change the generated output until you recompile.
+///
+/// **Pro Tip:** In some cases you can "trick" the compiler into triggering a rebuild when your
+/// `Cargo.toml` is changed by including this in your `src/main.rs` file
+/// `include_str!("../Cargo.toml");`
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # fn main() {
+/// let m = app_from_crate!().get_matches();
+/// # }
+/// ```
+#[cfg(not(feature = "no_cargo"))]
+#[macro_export]
+macro_rules! app_from_crate {
+ () => {
+ $crate::App::new(crate_name!())
+ .version(crate_version!())
+ .author(crate_authors!())
+ .about(crate_description!())
+ };
+ ($sep:expr) => {
+ $crate::App::new(crate_name!())
+ .version(crate_version!())
+ .author(crate_authors!($sep))
+ .about(crate_description!())
+ };
+}
+
+/// Build `App`, `Arg`s, `SubCommand`s and `Group`s with Usage-string like input
+/// but without the associated parsing runtime cost.
+///
+/// `clap_app!` also supports several shorthand syntaxes.
+///
+/// # Examples
+///
+/// ```no_run
+/// # #[macro_use]
+/// # extern crate clap;
+/// # fn main() {
+/// let matches = clap_app!(myapp =>
+/// (version: "1.0")
+/// (author: "Kevin K. <kbknapp@gmail.com>")
+/// (about: "Does awesome things")
+/// (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
+/// (@arg INPUT: +required "Sets the input file to use")
+/// (@arg debug: -d ... "Sets the level of debugging information")
+/// (@group difficulty =>
+/// (@arg hard: -h --hard "Sets hard mode")
+/// (@arg normal: -n --normal "Sets normal mode")
+/// (@arg easy: -e --easy "Sets easy mode")
+/// )
+/// (@subcommand test =>
+/// (about: "controls testing features")
+/// (version: "1.3")
+/// (author: "Someone E. <someone_else@other.com>")
+/// (@arg verbose: -v --verbose "Print test information verbosely")
+/// )
+/// )
+/// .get_matches();
+/// # }
+/// ```
+/// # Shorthand Syntax for Args
+///
+/// * A single hyphen followed by a character (such as `-c`) sets the [`Arg::short`]
+/// * A double hyphen followed by a character or word (such as `--config`) sets [`Arg::long`]
+/// * If one wishes to use a [`Arg::long`] with a hyphen inside (i.e. `--config-file`), you
+/// must use `--("config-file")` due to limitations of the Rust macro system.
+/// * Three dots (`...`) sets [`Arg::multiple(true)`]
+/// * Angled brackets after either a short or long will set [`Arg::value_name`] and
+/// `Arg::required(true)` such as `--config <FILE>` = `Arg::value_name("FILE")` and
+/// `Arg::required(true)`
+/// * Square brackets after either a short or long will set [`Arg::value_name`] and
+/// `Arg::required(false)` such as `--config [FILE]` = `Arg::value_name("FILE")` and
+/// `Arg::required(false)`
+/// * There are short hand syntaxes for Arg methods that accept booleans
+/// * A plus sign will set that method to `true` such as `+required` = `Arg::required(true)`
+/// * An exclamation will set that method to `false` such as `!required` = `Arg::required(false)`
+/// * A `#{min, max}` will set [`Arg::min_values(min)`] and [`Arg::max_values(max)`]
+/// * An asterisk (`*`) will set `Arg::required(true)`
+/// * Curly brackets around a `fn` will set [`Arg::validator`] as in `{fn}` = `Arg::validator(fn)`
+/// * An Arg method that accepts a string followed by square brackets will set that method such as
+/// `conflicts_with[FOO]` will set `Arg::conflicts_with("FOO")` (note the lack of quotes around
+/// `FOO` in the macro)
+/// * An Arg method that takes a string and can be set multiple times (such as
+/// [`Arg::conflicts_with`]) followed by square brackets and a list of values separated by spaces
+/// will set that method such as `conflicts_with[FOO BAR BAZ]` will set
+/// `Arg::conflicts_with("FOO")`, `Arg::conflicts_with("BAR")`, and `Arg::conflicts_with("BAZ")`
+/// (note the lack of quotes around the values in the macro)
+///
+/// # Shorthand Syntax for Groups
+///
+/// * There are short hand syntaxes for `ArgGroup` methods that accept booleans
+/// * A plus sign will set that method to `true` such as `+required` = `ArgGroup::required(true)`
+/// * An exclamation will set that method to `false` such as `!required` = `ArgGroup::required(false)`
+///
+/// [`Arg::short`]: ./struct.Arg.html#method.short
+/// [`Arg::long`]: ./struct.Arg.html#method.long
+/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
+/// [`Arg::value_name`]: ./struct.Arg.html#method.value_name
+/// [`Arg::min_values(min)`]: ./struct.Arg.html#method.min_values
+/// [`Arg::max_values(max)`]: ./struct.Arg.html#method.max_values
+/// [`Arg::validator`]: ./struct.Arg.html#method.validator
+/// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with
+#[macro_export]
+macro_rules! clap_app {
+ (@app ($builder:expr)) => { $builder };
+ (@app ($builder:expr) (@arg ($name:expr): $($tail:tt)*) $($tt:tt)*) => {
+ clap_app!{ @app
+ ($builder.arg(
+ clap_app!{ @arg ($crate::Arg::with_name($name)) (-) $($tail)* }))
+ $($tt)*
+ }
+ };
+ (@app ($builder:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => {
+ clap_app!{ @app
+ ($builder.arg(
+ clap_app!{ @arg ($crate::Arg::with_name(stringify!($name))) (-) $($tail)* }))
+ $($tt)*
+ }
+ };
+ (@app ($builder:expr) (@setting $setting:ident) $($tt:tt)*) => {
+ clap_app!{ @app
+ ($builder.setting($crate::AppSettings::$setting))
+ $($tt)*
+ }
+ };
+// Treat the application builder as an argument to set its attributes
+ (@app ($builder:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => {
+ clap_app!{ @app (clap_app!{ @arg ($builder) $($attr)* }) $($tt)* }
+ };
+ (@app ($builder:expr) (@group $name:ident => $($tail:tt)*) $($tt:tt)*) => {
+ clap_app!{ @app
+ (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name))) $($tail)* })
+ $($tt)*
+ }
+ };
+ (@app ($builder:expr) (@group $name:ident !$ident:ident => $($tail:tt)*) $($tt:tt)*) => {
+ clap_app!{ @app
+ (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name)).$ident(false)) $($tail)* })
+ $($tt)*
+ }
+ };
+ (@app ($builder:expr) (@group $name:ident +$ident:ident => $($tail:tt)*) $($tt:tt)*) => {
+ clap_app!{ @app
+ (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name)).$ident(true)) $($tail)* })
+ $($tt)*
+ }
+ };
+// Handle subcommand creation
+ (@app ($builder:expr) (@subcommand $name:ident => $($tail:tt)*) $($tt:tt)*) => {
+ clap_app!{ @app
+ ($builder.subcommand(
+ clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* }
+ ))
+ $($tt)*
+ }
+ };
+// Yaml like function calls - used for setting various meta directly against the app
+ (@app ($builder:expr) ($ident:ident: $($v:expr),*) $($tt:tt)*) => {
+// clap_app!{ @app ($builder.$ident($($v),*)) $($tt)* }
+ clap_app!{ @app
+ ($builder.$ident($($v),*))
+ $($tt)*
+ }
+ };
+
+// Add members to group and continue argument handling with the parent builder
+ (@group ($builder:expr, $group:expr)) => { $builder.group($group) };
+ // Treat the group builder as an argument to set its attributes
+ (@group ($builder:expr, $group:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => {
+ clap_app!{ @group ($builder, clap_app!{ @arg ($group) (-) $($attr)* }) $($tt)* }
+ };
+ (@group ($builder:expr, $group:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => {
+ clap_app!{ @group
+ (clap_app!{ @app ($builder) (@arg $name: $($tail)*) },
+ $group.arg(stringify!($name)))
+ $($tt)*
+ }
+ };
+
+// No more tokens to munch
+ (@arg ($arg:expr) $modes:tt) => { $arg };
+// Shorthand tokens influenced by the usage_string
+ (@arg ($arg:expr) $modes:tt --($long:expr) $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.long($long)) $modes $($tail)* }
+ };
+ (@arg ($arg:expr) $modes:tt --$long:ident $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.long(stringify!($long))) $modes $($tail)* }
+ };
+ (@arg ($arg:expr) $modes:tt -$short:ident $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.short(stringify!($short))) $modes $($tail)* }
+ };
+ (@arg ($arg:expr) (-) <$var:ident> $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value +required $($tail)* }
+ };
+ (@arg ($arg:expr) (+) <$var:ident> $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* }
+ };
+ (@arg ($arg:expr) (-) [$var:ident] $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value $($tail)* }
+ };
+ (@arg ($arg:expr) (+) [$var:ident] $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* }
+ };
+ (@arg ($arg:expr) $modes:tt ... $($tail:tt)*) => {
+ clap_app!{ @arg ($arg) $modes +multiple $($tail)* }
+ };
+// Shorthand magic
+ (@arg ($arg:expr) $modes:tt #{$n:expr, $m:expr} $($tail:tt)*) => {
+ clap_app!{ @arg ($arg) $modes min_values($n) max_values($m) $($tail)* }
+ };
+ (@arg ($arg:expr) $modes:tt * $($tail:tt)*) => {
+ clap_app!{ @arg ($arg) $modes +required $($tail)* }
+ };
+// !foo -> .foo(false)
+ (@arg ($arg:expr) $modes:tt !$ident:ident $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.$ident(false)) $modes $($tail)* }
+ };
+// +foo -> .foo(true)
+ (@arg ($arg:expr) $modes:tt +$ident:ident $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.$ident(true)) $modes $($tail)* }
+ };
+// Validator
+ (@arg ($arg:expr) $modes:tt {$fn_:expr} $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.validator($fn_)) $modes $($tail)* }
+ };
+ (@as_expr $expr:expr) => { $expr };
+// Help
+ (@arg ($arg:expr) $modes:tt $desc:tt) => { $arg.help(clap_app!{ @as_expr $desc }) };
+// Handle functions that need to be called multiple times for each argument
+ (@arg ($arg:expr) $modes:tt $ident:ident[$($target:ident)*] $($tail:tt)*) => {
+ clap_app!{ @arg ($arg $( .$ident(stringify!($target)) )*) $modes $($tail)* }
+ };
+// Inherit builder's functions, e.g. `index(2)`, `requires_if("val", "arg")`
+ (@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr),*) $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.$ident($($expr),*)) $modes $($tail)* }
+ };
+// Inherit builder's functions with trailing comma, e.g. `index(2,)`, `requires_if("val", "arg",)`
+ (@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr,)*) $($tail:tt)*) => {
+ clap_app!{ @arg ($arg.$ident($($expr),*)) $modes $($tail)* }
+ };
+
+// Build a subcommand outside of an app.
+ (@subcommand $name:ident => $($tail:tt)*) => {
+ clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* }
+ };
+// Start the magic
+ (($name:expr) => $($tail:tt)*) => {{
+ clap_app!{ @app ($crate::App::new($name)) $($tail)*}
+ }};
+
+ ($name:ident => $($tail:tt)*) => {{
+ clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)*}
+ }};
+}
+
+macro_rules! impl_settings {
+ ($n:ident, $($v:ident => $c:path),+) => {
+ pub fn set(&mut self, s: $n) {
+ match s {
+ $($n::$v => self.0.insert($c)),+
+ }
+ }
+
+ pub fn unset(&mut self, s: $n) {
+ match s {
+ $($n::$v => self.0.remove($c)),+
+ }
+ }
+
+ pub fn is_set(&self, s: $n) -> bool {
+ match s {
+ $($n::$v => self.0.contains($c)),+
+ }
+ }
+ };
+}
+
+// Convenience for writing to stderr thanks to https://github.com/BurntSushi
+macro_rules! wlnerr(
+ ($($arg:tt)*) => ({
+ use std::io::{Write, stderr};
+ writeln!(&mut stderr(), $($arg)*).ok();
+ })
+);
+
+#[cfg(feature = "debug")]
+#[cfg_attr(feature = "debug", macro_use)]
+#[cfg_attr(feature = "debug", allow(unused_macros))]
+mod debug_macros {
+ macro_rules! debugln {
+ ($fmt:expr) => (println!(concat!("DEBUG:clap:", $fmt)));
+ ($fmt:expr, $($arg:tt)*) => (println!(concat!("DEBUG:clap:",$fmt), $($arg)*));
+ }
+ macro_rules! sdebugln {
+ ($fmt:expr) => (println!($fmt));
+ ($fmt:expr, $($arg:tt)*) => (println!($fmt, $($arg)*));
+ }
+ macro_rules! debug {
+ ($fmt:expr) => (print!(concat!("DEBUG:clap:", $fmt)));
+ ($fmt:expr, $($arg:tt)*) => (print!(concat!("DEBUG:clap:",$fmt), $($arg)*));
+ }
+ macro_rules! sdebug {
+ ($fmt:expr) => (print!($fmt));
+ ($fmt:expr, $($arg:tt)*) => (print!($fmt, $($arg)*));
+ }
+}
+
+#[cfg(not(feature = "debug"))]
+#[cfg_attr(not(feature = "debug"), macro_use)]
+mod debug_macros {
+ macro_rules! debugln {
+ ($fmt:expr) => ();
+ ($fmt:expr, $($arg:tt)*) => ();
+ }
+ macro_rules! sdebugln {
+ ($fmt:expr) => ();
+ ($fmt:expr, $($arg:tt)*) => ();
+ }
+ macro_rules! debug {
+ ($fmt:expr) => ();
+ ($fmt:expr, $($arg:tt)*) => ();
+ }
+}
+
+// Helper/deduplication macro for printing the correct number of spaces in help messages
+// used in:
+// src/args/arg_builder/*.rs
+// src/app/mod.rs
+macro_rules! write_nspaces {
+ ($dst:expr, $num:expr) => ({
+ debugln!("write_spaces!: num={}", $num);
+ for _ in 0..$num {
+ $dst.write_all(b" ")?;
+ }
+ })
+}
+
+// convenience macro for remove an item from a vec
+//macro_rules! vec_remove_all {
+// ($vec:expr, $to_rem:expr) => {
+// debugln!("vec_remove_all! to_rem={:?}", $to_rem);
+// for i in (0 .. $vec.len()).rev() {
+// let should_remove = $to_rem.any(|name| name == &$vec[i]);
+// if should_remove { $vec.swap_remove(i); }
+// }
+// };
+//}
+macro_rules! find_from {
+ ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
+ let mut ret = None;
+ for k in $matcher.arg_names() {
+ if let Some(f) = find_by_name!($_self, k, flags, iter) {
+ if let Some(ref v) = f.$from() {
+ if v.contains($arg_name) {
+ ret = Some(f.to_string());
+ }
+ }
+ }
+ if let Some(o) = find_by_name!($_self, k, opts, iter) {
+ if let Some(ref v) = o.$from() {
+ if v.contains(&$arg_name) {
+ ret = Some(o.to_string());
+ }
+ }
+ }
+ if let Some(pos) = find_by_name!($_self, k, positionals, values) {
+ if let Some(ref v) = pos.$from() {
+ if v.contains($arg_name) {
+ ret = Some(pos.b.name.to_owned());
+ }
+ }
+ }
+ }
+ ret
+ }};
+}
+
+//macro_rules! find_name_from {
+// ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
+// let mut ret = None;
+// for k in $matcher.arg_names() {
+// if let Some(f) = find_by_name!($_self, k, flags, iter) {
+// if let Some(ref v) = f.$from() {
+// if v.contains($arg_name) {
+// ret = Some(f.b.name);
+// }
+// }
+// }
+// if let Some(o) = find_by_name!($_self, k, opts, iter) {
+// if let Some(ref v) = o.$from() {
+// if v.contains(&$arg_name) {
+// ret = Some(o.b.name);
+// }
+// }
+// }
+// if let Some(pos) = find_by_name!($_self, k, positionals, values) {
+// if let Some(ref v) = pos.$from() {
+// if v.contains($arg_name) {
+// ret = Some(pos.b.name);
+// }
+// }
+// }
+// }
+// ret
+// }};
+//}
+
+
+macro_rules! find_any_by_name {
+ ($p:expr, $name:expr) => {
+ {
+ fn as_trait_obj<'a, 'b, T: AnyArg<'a, 'b>>(x: &T) -> &AnyArg<'a, 'b> { x }
+ find_by_name!($p, $name, flags, iter).map(as_trait_obj).or(
+ find_by_name!($p, $name, opts, iter).map(as_trait_obj).or(
+ find_by_name!($p, $name, positionals, values).map(as_trait_obj)
+ )
+ )
+ }
+ }
+}
+// Finds an arg by name
+macro_rules! find_by_name {
+ ($p:expr, $name:expr, $what:ident, $how:ident) => {
+ $p.$what.$how().find(|o| o.b.name == $name)
+ }
+}
+
+// Finds an option including if it's aliased
+macro_rules! find_opt_by_long {
+ (@os $_self:ident, $long:expr) => {{
+ _find_by_long!($_self, $long, opts)
+ }};
+ ($_self:ident, $long:expr) => {{
+ _find_by_long!($_self, $long, opts)
+ }};
+}
+
+macro_rules! find_flag_by_long {
+ (@os $_self:ident, $long:expr) => {{
+ _find_by_long!($_self, $long, flags)
+ }};
+ ($_self:ident, $long:expr) => {{
+ _find_by_long!($_self, $long, flags)
+ }};
+}
+
+macro_rules! _find_by_long {
+ ($_self:ident, $long:expr, $what:ident) => {{
+ $_self.$what
+ .iter()
+ .filter(|a| a.s.long.is_some())
+ .find(|a| {
+ a.s.long.unwrap() == $long ||
+ (a.s.aliases.is_some() &&
+ a.s
+ .aliases
+ .as_ref()
+ .unwrap()
+ .iter()
+ .any(|&(alias, _)| alias == $long))
+ })
+ }}
+}
+
+// Finds an option
+macro_rules! find_opt_by_short {
+ ($_self:ident, $short:expr) => {{
+ _find_by_short!($_self, $short, opts)
+ }}
+}
+
+macro_rules! find_flag_by_short {
+ ($_self:ident, $short:expr) => {{
+ _find_by_short!($_self, $short, flags)
+ }}
+}
+
+macro_rules! _find_by_short {
+ ($_self:ident, $short:expr, $what:ident) => {{
+ $_self.$what
+ .iter()
+ .filter(|a| a.s.short.is_some())
+ .find(|a| a.s.short.unwrap() == $short)
+ }}
+}
+
+macro_rules! find_subcmd {
+ ($_self:expr, $sc:expr) => {{
+ $_self.subcommands
+ .iter()
+ .find(|s| {
+ &*s.p.meta.name == $sc ||
+ (s.p.meta.aliases.is_some() &&
+ s.p
+ .meta
+ .aliases
+ .as_ref()
+ .unwrap()
+ .iter()
+ .any(|&(n, _)| n == $sc))
+ })
+ }};
+}
+
+macro_rules! shorts {
+ ($_self:ident) => {{
+ _shorts_longs!($_self, short)
+ }};
+}
+
+
+macro_rules! longs {
+ ($_self:ident) => {{
+ _shorts_longs!($_self, long)
+ }};
+}
+
+macro_rules! _shorts_longs {
+ ($_self:ident, $what:ident) => {{
+ $_self.flags
+ .iter()
+ .filter(|f| f.s.$what.is_some())
+ .map(|f| f.s.$what.as_ref().unwrap())
+ .chain($_self.opts.iter()
+ .filter(|o| o.s.$what.is_some())
+ .map(|o| o.s.$what.as_ref().unwrap()))
+ }};
+}
+
+macro_rules! arg_names {
+ ($_self:ident) => {{
+ _names!(@args $_self)
+ }};
+}
+
+macro_rules! sc_names {
+ ($_self:ident) => {{
+ _names!(@sc $_self)
+ }};
+}
+
+macro_rules! _names {
+ (@args $_self:ident) => {{
+ $_self.flags
+ .iter()
+ .map(|f| &*f.b.name)
+ .chain($_self.opts.iter()
+ .map(|o| &*o.b.name)
+ .chain($_self.positionals.values()
+ .map(|p| &*p.b.name)))
+ }};
+ (@sc $_self:ident) => {{
+ $_self.subcommands
+ .iter()
+ .map(|s| &*s.p.meta.name)
+ .chain($_self.subcommands
+ .iter()
+ .filter(|s| s.p.meta.aliases.is_some())
+ .flat_map(|s| s.p.meta.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)))
+
+ }}
+}
diff --git a/clap/src/map.rs b/clap/src/map.rs
new file mode 100644
index 0000000..063a860
--- /dev/null
+++ b/clap/src/map.rs
@@ -0,0 +1,74 @@
+#[cfg(feature = "vec_map")]
+pub use vec_map::{Values, VecMap};
+
+#[cfg(not(feature = "vec_map"))]
+pub use self::vec_map::{Values, VecMap};
+
+#[cfg(not(feature = "vec_map"))]
+mod vec_map {
+ use std::collections::BTreeMap;
+ use std::collections::btree_map;
+ use std::fmt::{self, Debug, Formatter};
+
+ #[derive(Clone, Default, Debug)]
+ pub struct VecMap<V> {
+ inner: BTreeMap<usize, V>,
+ }
+
+ impl<V> VecMap<V> {
+ pub fn new() -> Self {
+ VecMap {
+ inner: Default::default(),
+ }
+ }
+
+ pub fn len(&self) -> usize { self.inner.len() }
+
+ pub fn is_empty(&self) -> bool { self.inner.is_empty() }
+
+ pub fn insert(&mut self, key: usize, value: V) -> Option<V> {
+ self.inner.insert(key, value)
+ }
+
+ pub fn values(&self) -> Values<V> { self.inner.values() }
+
+ pub fn iter(&self) -> Iter<V> {
+ Iter {
+ inner: self.inner.iter(),
+ }
+ }
+
+ pub fn contains_key(&self, key: usize) -> bool { self.inner.contains_key(&key) }
+
+ pub fn entry(&mut self, key: usize) -> Entry<V> { self.inner.entry(key) }
+
+ pub fn get(&self, key: usize) -> Option<&V> { self.inner.get(&key) }
+ }
+
+ pub type Values<'a, V> = btree_map::Values<'a, usize, V>;
+
+ pub type Entry<'a, V> = btree_map::Entry<'a, usize, V>;
+
+ #[derive(Clone)]
+ pub struct Iter<'a, V: 'a> {
+ inner: btree_map::Iter<'a, usize, V>,
+ }
+
+ impl<'a, V: 'a + Debug> Debug for Iter<'a, V> {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ f.debug_list().entries(self.inner.clone()).finish()
+ }
+ }
+
+ impl<'a, V: 'a> Iterator for Iter<'a, V> {
+ type Item = (usize, &'a V);
+
+ fn next(&mut self) -> Option<Self::Item> { self.inner.next().map(|(k, v)| (*k, v)) }
+ }
+
+ impl<'a, V: 'a> DoubleEndedIterator for Iter<'a, V> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.inner.next_back().map(|(k, v)| (*k, v))
+ }
+ }
+}
diff --git a/clap/src/osstringext.rs b/clap/src/osstringext.rs
new file mode 100644
index 0000000..061c01d
--- /dev/null
+++ b/clap/src/osstringext.rs
@@ -0,0 +1,119 @@
+#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
+use INVALID_UTF8;
+use std::ffi::OsStr;
+#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
+use std::os::unix::ffi::OsStrExt;
+
+#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
+pub trait OsStrExt3 {
+ fn from_bytes(b: &[u8]) -> &Self;
+ fn as_bytes(&self) -> &[u8];
+}
+
+#[doc(hidden)]
+pub trait OsStrExt2 {
+ fn starts_with(&self, s: &[u8]) -> bool;
+ fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr);
+ fn split_at(&self, i: usize) -> (&OsStr, &OsStr);
+ fn trim_left_matches(&self, b: u8) -> &OsStr;
+ fn contains_byte(&self, b: u8) -> bool;
+ fn split(&self, b: u8) -> OsSplit;
+}
+
+#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
+impl OsStrExt3 for OsStr {
+ fn from_bytes(b: &[u8]) -> &Self {
+ use std::mem;
+ unsafe { mem::transmute(b) }
+ }
+ fn as_bytes(&self) -> &[u8] {
+ self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8)
+ }
+}
+
+impl OsStrExt2 for OsStr {
+ fn starts_with(&self, s: &[u8]) -> bool {
+ self.as_bytes().starts_with(s)
+ }
+
+ fn contains_byte(&self, byte: u8) -> bool {
+ for b in self.as_bytes() {
+ if b == &byte {
+ return true;
+ }
+ }
+ false
+ }
+
+ fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) {
+ for (i, b) in self.as_bytes().iter().enumerate() {
+ if b == &byte {
+ return (
+ OsStr::from_bytes(&self.as_bytes()[..i]),
+ OsStr::from_bytes(&self.as_bytes()[i + 1..]),
+ );
+ }
+ }
+ (
+ &*self,
+ OsStr::from_bytes(&self.as_bytes()[self.len()..self.len()]),
+ )
+ }
+
+ fn trim_left_matches(&self, byte: u8) -> &OsStr {
+ let mut found = false;
+ for (i, b) in self.as_bytes().iter().enumerate() {
+ if b != &byte {
+ return OsStr::from_bytes(&self.as_bytes()[i..]);
+ } else {
+ found = true;
+ }
+ }
+ if found {
+ return OsStr::from_bytes(&self.as_bytes()[self.len()..]);
+ }
+ &*self
+ }
+
+ fn split_at(&self, i: usize) -> (&OsStr, &OsStr) {
+ (
+ OsStr::from_bytes(&self.as_bytes()[..i]),
+ OsStr::from_bytes(&self.as_bytes()[i..]),
+ )
+ }
+
+ fn split(&self, b: u8) -> OsSplit {
+ OsSplit {
+ sep: b,
+ val: self.as_bytes(),
+ pos: 0,
+ }
+ }
+}
+
+#[doc(hidden)]
+#[derive(Clone, Debug)]
+pub struct OsSplit<'a> {
+ sep: u8,
+ val: &'a [u8],
+ pos: usize,
+}
+
+impl<'a> Iterator for OsSplit<'a> {
+ type Item = &'a OsStr;
+
+ fn next(&mut self) -> Option<&'a OsStr> {
+ debugln!("OsSplit::next: self={:?}", self);
+ if self.pos == self.val.len() {
+ return None;
+ }
+ let start = self.pos;
+ for b in &self.val[start..] {
+ self.pos += 1;
+ if *b == self.sep {
+ return Some(OsStr::from_bytes(&self.val[start..self.pos - 1]));
+ }
+ }
+ Some(OsStr::from_bytes(&self.val[start..]))
+ }
+}
diff --git a/clap/src/strext.rs b/clap/src/strext.rs
new file mode 100644
index 0000000..6f81367
--- /dev/null
+++ b/clap/src/strext.rs
@@ -0,0 +1,16 @@
+pub trait _StrExt {
+ fn _is_char_boundary(&self, index: usize) -> bool;
+}
+
+impl _StrExt for str {
+ #[inline]
+ fn _is_char_boundary(&self, index: usize) -> bool {
+ if index == self.len() {
+ return true;
+ }
+ match self.as_bytes().get(index) {
+ None => false,
+ Some(&b) => b < 128 || b >= 192,
+ }
+ }
+}
diff --git a/clap/src/suggestions.rs b/clap/src/suggestions.rs
new file mode 100644
index 0000000..06071d2
--- /dev/null
+++ b/clap/src/suggestions.rs
@@ -0,0 +1,147 @@
+use app::App;
+// Third Party
+#[cfg(feature = "suggestions")]
+use strsim;
+
+// Internal
+use fmt::Format;
+
+/// Produces a string from a given list of possible values which is similar to
+/// the passed in value `v` with a certain confidence.
+/// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield
+/// `Some("foo")`, whereas "blark" would yield `None`.
+#[cfg(feature = "suggestions")]
+#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
+pub fn did_you_mean<'a, T: ?Sized, I>(v: &str, possible_values: I) -> Option<&'a str>
+where
+ T: AsRef<str> + 'a,
+ I: IntoIterator<Item = &'a T>,
+{
+ let mut candidate: Option<(f64, &str)> = None;
+ for pv in possible_values {
+ let confidence = strsim::jaro_winkler(v, pv.as_ref());
+ if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence))
+ {
+ candidate = Some((confidence, pv.as_ref()));
+ }
+ }
+ match candidate {
+ None => None,
+ Some((_, candidate)) => Some(candidate),
+ }
+}
+
+#[cfg(not(feature = "suggestions"))]
+pub fn did_you_mean<'a, T: ?Sized, I>(_: &str, _: I) -> Option<&'a str>
+where
+ T: AsRef<str> + 'a,
+ I: IntoIterator<Item = &'a T>,
+{
+ None
+}
+
+/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
+#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
+pub fn did_you_mean_flag_suffix<'z, T, I>(
+ arg: &str,
+ args_rest: &'z [&str],
+ longs: I,
+ subcommands: &'z [App],
+) -> (String, Option<&'z str>)
+where
+ T: AsRef<str> + 'z,
+ I: IntoIterator<Item = &'z T>,
+{
+ if let Some(candidate) = did_you_mean(arg, longs) {
+ let suffix = format!(
+ "\n\tDid you mean {}{}?",
+ Format::Good("--"),
+ Format::Good(candidate)
+ );
+ return (suffix, Some(candidate));
+ }
+
+ subcommands
+ .into_iter()
+ .filter_map(|subcommand| {
+ let opts = subcommand
+ .p
+ .flags
+ .iter()
+ .filter_map(|f| f.s.long)
+ .chain(subcommand.p.opts.iter().filter_map(|o| o.s.long));
+
+ let candidate = match did_you_mean(arg, opts) {
+ Some(candidate) => candidate,
+ None => return None
+ };
+ let score = match args_rest.iter().position(|x| *x == subcommand.get_name()) {
+ Some(score) => score,
+ None => return None
+ };
+
+ let suffix = format!(
+ "\n\tDid you mean to put '{}{}' after the subcommand '{}'?",
+ Format::Good("--"),
+ Format::Good(candidate),
+ Format::Good(subcommand.get_name())
+ );
+
+ Some((score, (suffix, Some(candidate))))
+ })
+ .min_by_key(|&(score, _)| score)
+ .map(|(_, suggestion)| suggestion)
+ .unwrap_or_else(|| (String::new(), None))
+}
+
+/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
+pub fn did_you_mean_value_suffix<'z, T, I>(arg: &str, values: I) -> (String, Option<&'z str>)
+where
+ T: AsRef<str> + 'z,
+ I: IntoIterator<Item = &'z T>,
+{
+ match did_you_mean(arg, values) {
+ Some(candidate) => {
+ let suffix = format!("\n\tDid you mean '{}'?", Format::Good(candidate));
+ (suffix, Some(candidate))
+ }
+ None => (String::new(), None),
+ }
+}
+
+#[cfg(all(test, features = "suggestions"))]
+mod test {
+ use super::*;
+
+ #[test]
+ fn possible_values_match() {
+ let p_vals = ["test", "possible", "values"];
+ assert_eq!(did_you_mean("tst", p_vals.iter()), Some("test"));
+ }
+
+ #[test]
+ fn possible_values_nomatch() {
+ let p_vals = ["test", "possible", "values"];
+ assert!(did_you_mean("hahaahahah", p_vals.iter()).is_none());
+ }
+
+ #[test]
+ fn suffix_long() {
+ let p_vals = ["test", "possible", "values"];
+ let suffix = "\n\tDid you mean \'--test\'?";
+ assert_eq!(
+ did_you_mean_flag_suffix("tst", p_vals.iter(), []),
+ (suffix, Some("test"))
+ );
+ }
+
+ #[test]
+ fn suffix_enum() {
+ let p_vals = ["test", "possible", "values"];
+ let suffix = "\n\tDid you mean \'test\'?";
+ assert_eq!(
+ did_you_mean_value_suffix("tst", p_vals.iter()),
+ (suffix, Some("test"))
+ );
+ }
+}
diff --git a/clap/src/usage_parser.rs b/clap/src/usage_parser.rs
new file mode 100644
index 0000000..f6d5ac6
--- /dev/null
+++ b/clap/src/usage_parser.rs
@@ -0,0 +1,1347 @@
+// Internal
+use INTERNAL_ERROR_MSG;
+use args::Arg;
+use args::settings::ArgSettings;
+use map::VecMap;
+
+#[derive(PartialEq, Debug)]
+enum UsageToken {
+ Name,
+ ValName,
+ Short,
+ Long,
+ Help,
+ Multiple,
+ Unknown,
+}
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct UsageParser<'a> {
+ usage: &'a str,
+ pos: usize,
+ start: usize,
+ prev: UsageToken,
+ explicit_name_set: bool,
+}
+
+impl<'a> UsageParser<'a> {
+ fn new(usage: &'a str) -> Self {
+ debugln!("UsageParser::new: usage={:?}", usage);
+ UsageParser {
+ usage: usage,
+ pos: 0,
+ start: 0,
+ prev: UsageToken::Unknown,
+ explicit_name_set: false,
+ }
+ }
+
+ pub fn from_usage(usage: &'a str) -> Self {
+ debugln!("UsageParser::from_usage;");
+ UsageParser::new(usage)
+ }
+
+ pub fn parse(mut self) -> Arg<'a, 'a> {
+ debugln!("UsageParser::parse;");
+ let mut arg = Arg::default();
+ loop {
+ debugln!("UsageParser::parse:iter: pos={};", self.pos);
+ self.stop_at(token);
+ if let Some(&c) = self.usage.as_bytes().get(self.pos) {
+ match c {
+ b'-' => self.short_or_long(&mut arg),
+ b'.' => self.multiple(&mut arg),
+ b'\'' => self.help(&mut arg),
+ _ => self.name(&mut arg),
+ }
+ } else {
+ break;
+ }
+ }
+ debug_assert!(
+ !arg.b.name.is_empty(),
+ format!(
+ "No name found for Arg when parsing usage string: {}",
+ self.usage
+ )
+ );
+ arg.v.num_vals = match arg.v.val_names {
+ Some(ref v) if v.len() >= 2 => Some(v.len() as u64),
+ _ => None,
+ };
+ debugln!("UsageParser::parse: vals...{:?}", arg.v.val_names);
+ arg
+ }
+
+ fn name(&mut self, arg: &mut Arg<'a, 'a>) {
+ debugln!("UsageParser::name;");
+ if *self.usage
+ .as_bytes()
+ .get(self.pos)
+ .expect(INTERNAL_ERROR_MSG) == b'<' && !self.explicit_name_set
+ {
+ arg.setb(ArgSettings::Required);
+ }
+ self.pos += 1;
+ self.stop_at(name_end);
+ let name = &self.usage[self.start..self.pos];
+ if self.prev == UsageToken::Unknown {
+ debugln!("UsageParser::name: setting name...{}", name);
+ arg.b.name = name;
+ if arg.s.long.is_none() && arg.s.short.is_none() {
+ debugln!("UsageParser::name: explicit name set...");
+ self.explicit_name_set = true;
+ self.prev = UsageToken::Name;
+ }
+ } else {
+ debugln!("UsageParser::name: setting val name...{}", name);
+ if let Some(ref mut v) = arg.v.val_names {
+ let len = v.len();
+ v.insert(len, name);
+ } else {
+ let mut v = VecMap::new();
+ v.insert(0, name);
+ arg.v.val_names = Some(v);
+ arg.setb(ArgSettings::TakesValue);
+ }
+ self.prev = UsageToken::ValName;
+ }
+ }
+
+ fn stop_at<F>(&mut self, f: F)
+ where
+ F: Fn(u8) -> bool,
+ {
+ debugln!("UsageParser::stop_at;");
+ self.start = self.pos;
+ self.pos += self.usage[self.start..]
+ .bytes()
+ .take_while(|&b| f(b))
+ .count();
+ }
+
+ fn short_or_long(&mut self, arg: &mut Arg<'a, 'a>) {
+ debugln!("UsageParser::short_or_long;");
+ self.pos += 1;
+ if *self.usage
+ .as_bytes()
+ .get(self.pos)
+ .expect(INTERNAL_ERROR_MSG) == b'-'
+ {
+ self.pos += 1;
+ self.long(arg);
+ return;
+ }
+ self.short(arg)
+ }
+
+ fn long(&mut self, arg: &mut Arg<'a, 'a>) {
+ debugln!("UsageParser::long;");
+ self.stop_at(long_end);
+ let name = &self.usage[self.start..self.pos];
+ if !self.explicit_name_set {
+ debugln!("UsageParser::long: setting name...{}", name);
+ arg.b.name = name;
+ }
+ debugln!("UsageParser::long: setting long...{}", name);
+ arg.s.long = Some(name);
+ self.prev = UsageToken::Long;
+ }
+
+ fn short(&mut self, arg: &mut Arg<'a, 'a>) {
+ debugln!("UsageParser::short;");
+ let start = &self.usage[self.pos..];
+ let short = start.chars().nth(0).expect(INTERNAL_ERROR_MSG);
+ debugln!("UsageParser::short: setting short...{}", short);
+ arg.s.short = Some(short);
+ if arg.b.name.is_empty() {
+ // --long takes precedence but doesn't set self.explicit_name_set
+ let name = &start[..short.len_utf8()];
+ debugln!("UsageParser::short: setting name...{}", name);
+ arg.b.name = name;
+ }
+ self.prev = UsageToken::Short;
+ }
+
+ // "something..."
+ fn multiple(&mut self, arg: &mut Arg) {
+ debugln!("UsageParser::multiple;");
+ let mut dot_counter = 1;
+ let start = self.pos;
+ let mut bytes = self.usage[start..].bytes();
+ while bytes.next() == Some(b'.') {
+ dot_counter += 1;
+ self.pos += 1;
+ if dot_counter == 3 {
+ debugln!("UsageParser::multiple: setting multiple");
+ arg.setb(ArgSettings::Multiple);
+ if arg.is_set(ArgSettings::TakesValue) {
+ arg.setb(ArgSettings::UseValueDelimiter);
+ arg.unsetb(ArgSettings::ValueDelimiterNotSet);
+ if arg.v.val_delim.is_none() {
+ arg.v.val_delim = Some(',');
+ }
+ }
+ self.prev = UsageToken::Multiple;
+ self.pos += 1;
+ break;
+ }
+ }
+ }
+
+ fn help(&mut self, arg: &mut Arg<'a, 'a>) {
+ debugln!("UsageParser::help;");
+ self.stop_at(help_start);
+ self.start = self.pos + 1;
+ self.pos = self.usage.len() - 1;
+ debugln!(
+ "UsageParser::help: setting help...{}",
+ &self.usage[self.start..self.pos]
+ );
+ arg.b.help = Some(&self.usage[self.start..self.pos]);
+ self.pos += 1; // Move to next byte to keep from thinking ending ' is a start
+ self.prev = UsageToken::Help;
+ }
+}
+
+#[inline]
+fn name_end(b: u8) -> bool { b != b']' && b != b'>' }
+
+#[inline]
+fn token(b: u8) -> bool { b != b'\'' && b != b'.' && b != b'<' && b != b'[' && b != b'-' }
+
+#[inline]
+fn long_end(b: u8) -> bool {
+ b != b'\'' && b != b'.' && b != b'<' && b != b'[' && b != b'=' && b != b' '
+}
+
+#[inline]
+fn help_start(b: u8) -> bool { b != b'\'' }
+
+#[cfg(test)]
+mod test {
+ use args::Arg;
+ use args::ArgSettings;
+
+ #[test]
+ fn create_flag_usage() {
+ let a = Arg::from_usage("[flag] -f 'some help info'");
+ assert_eq!(a.b.name, "flag");
+ assert_eq!(a.s.short.unwrap(), 'f');
+ assert!(a.s.long.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.v.val_names.is_none());
+ assert!(a.v.num_vals.is_none());
+
+ let b = Arg::from_usage("[flag] --flag 'some help info'");
+ assert_eq!(b.b.name, "flag");
+ assert_eq!(b.s.long.unwrap(), "flag");
+ assert!(b.s.short.is_none());
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(a.v.val_names.is_none());
+ assert!(a.v.num_vals.is_none());
+
+ let b = Arg::from_usage("--flag 'some help info'");
+ assert_eq!(b.b.name, "flag");
+ assert_eq!(b.s.long.unwrap(), "flag");
+ assert!(b.s.short.is_none());
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(b.v.val_names.is_none());
+ assert!(b.v.num_vals.is_none());
+
+ let c = Arg::from_usage("[flag] -f --flag 'some help info'");
+ assert_eq!(c.b.name, "flag");
+ assert_eq!(c.s.short.unwrap(), 'f');
+ assert_eq!(c.s.long.unwrap(), "flag");
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(!c.is_set(ArgSettings::Multiple));
+ assert!(c.v.val_names.is_none());
+ assert!(c.v.num_vals.is_none());
+
+ let d = Arg::from_usage("[flag] -f... 'some help info'");
+ assert_eq!(d.b.name, "flag");
+ assert_eq!(d.s.short.unwrap(), 'f');
+ assert!(d.s.long.is_none());
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.v.val_names.is_none());
+ assert!(d.v.num_vals.is_none());
+
+ let e = Arg::from_usage("[flag] -f --flag... 'some help info'");
+ assert_eq!(e.b.name, "flag");
+ assert_eq!(e.s.long.unwrap(), "flag");
+ assert_eq!(e.s.short.unwrap(), 'f');
+ assert_eq!(e.b.help.unwrap(), "some help info");
+ assert!(e.is_set(ArgSettings::Multiple));
+ assert!(e.v.val_names.is_none());
+ assert!(e.v.num_vals.is_none());
+
+ let e = Arg::from_usage("-f --flag... 'some help info'");
+ assert_eq!(e.b.name, "flag");
+ assert_eq!(e.s.long.unwrap(), "flag");
+ assert_eq!(e.s.short.unwrap(), 'f');
+ assert_eq!(e.b.help.unwrap(), "some help info");
+ assert!(e.is_set(ArgSettings::Multiple));
+ assert!(e.v.val_names.is_none());
+ assert!(e.v.num_vals.is_none());
+
+ let e = Arg::from_usage("--flags");
+ assert_eq!(e.b.name, "flags");
+ assert_eq!(e.s.long.unwrap(), "flags");
+ assert!(e.v.val_names.is_none());
+ assert!(e.v.num_vals.is_none());
+
+ let e = Arg::from_usage("--flags...");
+ assert_eq!(e.b.name, "flags");
+ assert_eq!(e.s.long.unwrap(), "flags");
+ assert!(e.is_set(ArgSettings::Multiple));
+ assert!(e.v.val_names.is_none());
+ assert!(e.v.num_vals.is_none());
+
+ let e = Arg::from_usage("[flags] -f");
+ assert_eq!(e.b.name, "flags");
+ assert_eq!(e.s.short.unwrap(), 'f');
+ assert!(e.v.val_names.is_none());
+ assert!(e.v.num_vals.is_none());
+
+ let e = Arg::from_usage("[flags] -f...");
+ assert_eq!(e.b.name, "flags");
+ assert_eq!(e.s.short.unwrap(), 'f');
+ assert!(e.is_set(ArgSettings::Multiple));
+ assert!(e.v.val_names.is_none());
+ assert!(e.v.num_vals.is_none());
+
+ let a = Arg::from_usage("-f 'some help info'");
+ assert_eq!(a.b.name, "f");
+ assert_eq!(a.s.short.unwrap(), 'f');
+ assert!(a.s.long.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.v.val_names.is_none());
+ assert!(a.v.num_vals.is_none());
+
+ let e = Arg::from_usage("-f");
+ assert_eq!(e.b.name, "f");
+ assert_eq!(e.s.short.unwrap(), 'f');
+ assert!(e.v.val_names.is_none());
+ assert!(e.v.num_vals.is_none());
+
+ let e = Arg::from_usage("-f...");
+ assert_eq!(e.b.name, "f");
+ assert_eq!(e.s.short.unwrap(), 'f');
+ assert!(e.is_set(ArgSettings::Multiple));
+ assert!(e.v.val_names.is_none());
+ assert!(e.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage0() {
+ // Short only
+ let a = Arg::from_usage("[option] -o [opt] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.short.unwrap(), 'o');
+ assert!(a.s.long.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage1() {
+ let b = Arg::from_usage("-o [opt] 'some help info'");
+ assert_eq!(b.b.name, "o");
+ assert_eq!(b.s.short.unwrap(), 'o');
+ assert!(b.s.long.is_none());
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage2() {
+ let c = Arg::from_usage("<option> -o <opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.short.unwrap(), 'o');
+ assert!(c.s.long.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(!c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage3() {
+ let d = Arg::from_usage("-o <opt> 'some help info'");
+ assert_eq!(d.b.name, "o");
+ assert_eq!(d.s.short.unwrap(), 'o');
+ assert!(d.s.long.is_none());
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(!d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage4() {
+ let a = Arg::from_usage("[option] -o [opt]... 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.short.unwrap(), 'o');
+ assert!(a.s.long.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage5() {
+ let a = Arg::from_usage("[option]... -o [opt] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.short.unwrap(), 'o');
+ assert!(a.s.long.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage6() {
+ let b = Arg::from_usage("-o [opt]... 'some help info'");
+ assert_eq!(b.b.name, "o");
+ assert_eq!(b.s.short.unwrap(), 'o');
+ assert!(b.s.long.is_none());
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage7() {
+ let c = Arg::from_usage("<option> -o <opt>... 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.short.unwrap(), 'o');
+ assert!(c.s.long.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage8() {
+ let c = Arg::from_usage("<option>... -o <opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.short.unwrap(), 'o');
+ assert!(c.s.long.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage9() {
+ let d = Arg::from_usage("-o <opt>... 'some help info'");
+ assert_eq!(d.b.name, "o");
+ assert_eq!(d.s.short.unwrap(), 'o');
+ assert!(d.s.long.is_none());
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long1() {
+ let a = Arg::from_usage("[option] --opt [opt] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert!(a.s.short.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long2() {
+ let b = Arg::from_usage("--opt [option] 'some help info'");
+ assert_eq!(b.b.name, "opt");
+ assert_eq!(b.s.long.unwrap(), "opt");
+ assert!(b.s.short.is_none());
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long3() {
+ let c = Arg::from_usage("<option> --opt <opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert!(c.s.short.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(!c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long4() {
+ let d = Arg::from_usage("--opt <option> 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert!(d.s.short.is_none());
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(!d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long5() {
+ let a = Arg::from_usage("[option] --opt [opt]... 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert!(a.s.short.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long6() {
+ let a = Arg::from_usage("[option]... --opt [opt] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert!(a.s.short.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long7() {
+ let b = Arg::from_usage("--opt [option]... 'some help info'");
+ assert_eq!(b.b.name, "opt");
+ assert_eq!(b.s.long.unwrap(), "opt");
+ assert!(b.s.short.is_none());
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long8() {
+ let c = Arg::from_usage("<option> --opt <opt>... 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert!(c.s.short.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long9() {
+ let c = Arg::from_usage("<option>... --opt <opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert!(c.s.short.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long10() {
+ let d = Arg::from_usage("--opt <option>... 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert!(d.s.short.is_none());
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals1() {
+ let a = Arg::from_usage("[option] --opt=[opt] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert!(a.s.short.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals2() {
+ let b = Arg::from_usage("--opt=[option] 'some help info'");
+ assert_eq!(b.b.name, "opt");
+ assert_eq!(b.s.long.unwrap(), "opt");
+ assert!(b.s.short.is_none());
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals3() {
+ let c = Arg::from_usage("<option> --opt=<opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert!(c.s.short.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(!c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals4() {
+ let d = Arg::from_usage("--opt=<option> 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert!(d.s.short.is_none());
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(!d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals5() {
+ let a = Arg::from_usage("[option] --opt=[opt]... 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert!(a.s.short.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals6() {
+ let a = Arg::from_usage("[option]... --opt=[opt] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert!(a.s.short.is_none());
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals7() {
+ let b = Arg::from_usage("--opt=[option]... 'some help info'");
+ assert_eq!(b.b.name, "opt");
+ assert_eq!(b.s.long.unwrap(), "opt");
+ assert!(b.s.short.is_none());
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals8() {
+ let c = Arg::from_usage("<option> --opt=<opt>... 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert!(c.s.short.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals9() {
+ let c = Arg::from_usage("<option>... --opt=<opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert!(c.s.short.is_none());
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_long_equals10() {
+ let d = Arg::from_usage("--opt=<option>... 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert!(d.s.short.is_none());
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both1() {
+ let a = Arg::from_usage("[option] -o --opt [option] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert_eq!(a.s.short.unwrap(), 'o');
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both2() {
+ let b = Arg::from_usage("-o --opt [option] 'some help info'");
+ assert_eq!(b.b.name, "opt");
+ assert_eq!(b.s.long.unwrap(), "opt");
+ assert_eq!(b.s.short.unwrap(), 'o');
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both3() {
+ let c = Arg::from_usage("<option> -o --opt <opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert_eq!(c.s.short.unwrap(), 'o');
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(!c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both4() {
+ let d = Arg::from_usage("-o --opt <option> 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert_eq!(d.s.short.unwrap(), 'o');
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(!d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both5() {
+ let a = Arg::from_usage("[option]... -o --opt [option] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert_eq!(a.s.short.unwrap(), 'o');
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both6() {
+ let b = Arg::from_usage("-o --opt [option]... 'some help info'");
+ assert_eq!(b.b.name, "opt");
+ assert_eq!(b.s.long.unwrap(), "opt");
+ assert_eq!(b.s.short.unwrap(), 'o');
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both7() {
+ let c = Arg::from_usage("<option>... -o --opt <opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert_eq!(c.s.short.unwrap(), 'o');
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both8() {
+ let d = Arg::from_usage("-o --opt <option>... 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert_eq!(d.s.short.unwrap(), 'o');
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both_equals1() {
+ let a = Arg::from_usage("[option] -o --opt=[option] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert_eq!(a.s.short.unwrap(), 'o');
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both_equals2() {
+ let b = Arg::from_usage("-o --opt=[option] 'some help info'");
+ assert_eq!(b.b.name, "opt");
+ assert_eq!(b.s.long.unwrap(), "opt");
+ assert_eq!(b.s.short.unwrap(), 'o');
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both_equals3() {
+ let c = Arg::from_usage("<option> -o --opt=<opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert_eq!(c.s.short.unwrap(), 'o');
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(!c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both_equals4() {
+ let d = Arg::from_usage("-o --opt=<option> 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert_eq!(d.s.short.unwrap(), 'o');
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(!d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both_equals5() {
+ let a = Arg::from_usage("[option]... -o --opt=[option] 'some help info'");
+ assert_eq!(a.b.name, "option");
+ assert_eq!(a.s.long.unwrap(), "opt");
+ assert_eq!(a.s.short.unwrap(), 'o');
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(a.is_set(ArgSettings::Multiple));
+ assert!(a.is_set(ArgSettings::TakesValue));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both_equals6() {
+ let b = Arg::from_usage("-o --opt=[option]... 'some help info'");
+ assert_eq!(b.b.name, "opt");
+ assert_eq!(b.s.long.unwrap(), "opt");
+ assert_eq!(b.s.short.unwrap(), 'o');
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::TakesValue));
+ assert!(!b.is_set(ArgSettings::Required));
+ assert_eq!(
+ b.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both_equals7() {
+ let c = Arg::from_usage("<option>... -o --opt=<opt> 'some help info'");
+ assert_eq!(c.b.name, "option");
+ assert_eq!(c.s.long.unwrap(), "opt");
+ assert_eq!(c.s.short.unwrap(), 'o');
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(c.is_set(ArgSettings::TakesValue));
+ assert!(c.is_set(ArgSettings::Required));
+ assert_eq!(
+ c.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"opt"]
+ );
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_usage_both_equals8() {
+ let d = Arg::from_usage("-o --opt=<option>... 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert_eq!(d.s.short.unwrap(), 'o');
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"option"]
+ );
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_option_with_vals1() {
+ let d = Arg::from_usage("-o <file> <mode> 'some help info'");
+ assert_eq!(d.b.name, "o");
+ assert!(d.s.long.is_none());
+ assert_eq!(d.s.short.unwrap(), 'o');
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(!d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"file", &"mode"]
+ );
+ assert_eq!(d.v.num_vals.unwrap(), 2);
+ }
+
+ #[test]
+ fn create_option_with_vals2() {
+ let d = Arg::from_usage("-o <file> <mode>... 'some help info'");
+ assert_eq!(d.b.name, "o");
+ assert!(d.s.long.is_none());
+ assert_eq!(d.s.short.unwrap(), 'o');
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"file", &"mode"]
+ );
+ assert_eq!(d.v.num_vals.unwrap(), 2);
+ }
+
+ #[test]
+ fn create_option_with_vals3() {
+ let d = Arg::from_usage("--opt <file> <mode>... 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert!(d.s.short.is_none());
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"file", &"mode"]
+ );
+ assert_eq!(d.v.num_vals.unwrap(), 2);
+ }
+
+ #[test]
+ fn create_option_with_vals4() {
+ let d = Arg::from_usage("[myopt] --opt <file> <mode> 'some help info'");
+ assert_eq!(d.b.name, "myopt");
+ assert!(d.s.short.is_none());
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(!d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(!d.is_set(ArgSettings::Required));
+ assert_eq!(
+ d.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"file", &"mode"]
+ );
+ assert_eq!(d.v.num_vals.unwrap(), 2);
+ }
+
+ #[test]
+ fn create_option_with_vals5() {
+ let d = Arg::from_usage("--opt <file> <mode> 'some help info'");
+ assert_eq!(d.b.name, "opt");
+ assert!(d.s.short.is_none());
+ assert_eq!(d.s.long.unwrap(), "opt");
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(!d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::TakesValue));
+ assert!(d.is_set(ArgSettings::Required));
+ assert_eq!(d.v.num_vals.unwrap(), 2);
+ }
+
+ #[test]
+ fn create_positional_usage() {
+ let a = Arg::from_usage("[pos] 'some help info'");
+ assert_eq!(a.b.name, "pos");
+ assert_eq!(a.b.help.unwrap(), "some help info");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(!a.is_set(ArgSettings::Required));
+ assert!(a.v.val_names.is_none());
+ assert!(a.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn create_positional_usage0() {
+ let b = Arg::from_usage("<pos> 'some help info'");
+ assert_eq!(b.b.name, "pos");
+ assert_eq!(b.b.help.unwrap(), "some help info");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::Required));
+ assert!(b.v.val_names.is_none());
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn pos_mult_help() {
+ let c = Arg::from_usage("[pos]... 'some help info'");
+ assert_eq!(c.b.name, "pos");
+ assert_eq!(c.b.help.unwrap(), "some help info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(!c.is_set(ArgSettings::Required));
+ assert!(c.v.val_names.is_none());
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn pos_help_lit_single_quote() {
+ let c = Arg::from_usage("[pos]... 'some help\' info'");
+ assert_eq!(c.b.name, "pos");
+ assert_eq!(c.b.help.unwrap(), "some help' info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(!c.is_set(ArgSettings::Required));
+ assert!(c.v.val_names.is_none());
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn pos_help_double_lit_single_quote() {
+ let c = Arg::from_usage("[pos]... 'some \'help\' info'");
+ assert_eq!(c.b.name, "pos");
+ assert_eq!(c.b.help.unwrap(), "some 'help' info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(!c.is_set(ArgSettings::Required));
+ assert!(c.v.val_names.is_none());
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn pos_help_newline() {
+ let c = Arg::from_usage(
+ "[pos]... 'some help{n}\
+ info'",
+ );
+ assert_eq!(c.b.name, "pos");
+ assert_eq!(c.b.help.unwrap(), "some help{n}info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(!c.is_set(ArgSettings::Required));
+ assert!(c.v.val_names.is_none());
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn pos_help_newline_lit_sq() {
+ let c = Arg::from_usage(
+ "[pos]... 'some help\' stuff{n}\
+ info'",
+ );
+ assert_eq!(c.b.name, "pos");
+ assert_eq!(c.b.help.unwrap(), "some help' stuff{n}info");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(!c.is_set(ArgSettings::Required));
+ assert!(c.v.val_names.is_none());
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn pos_req_mult_help() {
+ let d = Arg::from_usage("<pos>... 'some help info'");
+ assert_eq!(d.b.name, "pos");
+ assert_eq!(d.b.help.unwrap(), "some help info");
+ assert!(d.is_set(ArgSettings::Multiple));
+ assert!(d.is_set(ArgSettings::Required));
+ assert!(d.v.val_names.is_none());
+ assert!(d.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn pos_req() {
+ let b = Arg::from_usage("<pos>");
+ assert_eq!(b.b.name, "pos");
+ assert!(!b.is_set(ArgSettings::Multiple));
+ assert!(b.is_set(ArgSettings::Required));
+ assert!(b.v.val_names.is_none());
+ assert!(b.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn pos_mult() {
+ let c = Arg::from_usage("[pos]...");
+ assert_eq!(c.b.name, "pos");
+ assert!(c.is_set(ArgSettings::Multiple));
+ assert!(!c.is_set(ArgSettings::Required));
+ assert!(c.v.val_names.is_none());
+ assert!(c.v.num_vals.is_none());
+ }
+
+ #[test]
+ fn nonascii() {
+ let a = Arg::from_usage("<ASCII> 'üñíčöĐ€'");
+ assert_eq!(a.b.name, "ASCII");
+ assert_eq!(a.b.help, Some("üñíčöĐ€"));
+ let a = Arg::from_usage("<üñíčöĐ€> 'ASCII'");
+ assert_eq!(a.b.name, "üñíčöĐ€");
+ assert_eq!(a.b.help, Some("ASCII"));
+ let a = Arg::from_usage("<üñíčöĐ€> 'üñíčöĐ€'");
+ assert_eq!(a.b.name, "üñíčöĐ€");
+ assert_eq!(a.b.help, Some("üñíčöĐ€"));
+ let a = Arg::from_usage("-ø 'ø'");
+ assert_eq!(a.b.name, "ø");
+ assert_eq!(a.s.short, Some('ø'));
+ assert_eq!(a.b.help, Some("ø"));
+ let a = Arg::from_usage("--üñíčöĐ€ 'Nōṫ ASCII'");
+ assert_eq!(a.b.name, "üñíčöĐ€");
+ assert_eq!(a.s.long, Some("üñíčöĐ€"));
+ assert_eq!(a.b.help, Some("Nōṫ ASCII"));
+ let a = Arg::from_usage("[ñämê] --ôpt=[üñíčöĐ€] 'hælp'");
+ assert_eq!(a.b.name, "ñämê");
+ assert_eq!(a.s.long, Some("ôpt"));
+ assert_eq!(
+ a.v.val_names.unwrap().values().collect::<Vec<_>>(),
+ [&"üñíčöĐ€"]
+ );
+ assert_eq!(a.b.help, Some("hælp"));
+ }
+}
diff --git a/clap/tests/app.yml b/clap/tests/app.yml
new file mode 100644
index 0000000..850bb82
--- /dev/null
+++ b/clap/tests/app.yml
@@ -0,0 +1,121 @@
+name: claptests
+version: "1.0"
+about: tests clap library
+author: Kevin K. <kbknapp@gmail.com>
+settings:
+ - ArgRequiredElseHelp
+help_message: prints help with a nonstandard description
+args:
+ - opt:
+ short: o
+ long: option
+ multiple: true
+ help: tests options
+ - positional:
+ help: tests positionals
+ index: 1
+ - positional2:
+ help: tests positionals with exclusions
+ index: 2
+ default_value_if:
+ - [flag, Null, some]
+ - [postional, other, something]
+ - flag:
+ short: f
+ long: flag
+ multiple: true
+ help: tests flags
+ global: true
+ - flag2:
+ short: F
+ help: tests flags with exclusions
+ conflicts_with:
+ - flag
+ requires:
+ - option2
+ - option2:
+ long: long-option-2
+ help: tests long options with exclusions
+ conflicts_with:
+ - option
+ requires:
+ - positional2
+ - option3:
+ short: O
+ long: Option
+ help: tests options with specific value sets
+ takes_value: true
+ possible_values:
+ - fast
+ - slow
+ requires_if:
+ - [fast, flag]
+ - positional3:
+ index: 3
+ help: tests positionals with specific values
+ possible_values: [ vi, emacs ]
+ - multvals:
+ long: multvals
+ help: Tests multiple values, not mult occs
+ value_names:
+ - one
+ - two
+ - multvalsmo:
+ long: multvalsmo
+ multiple: true
+ help: Tests multiple values, not mult occs
+ value_names: [one, two]
+ - multvalsdelim:
+ long: multvalsdelim
+ help: Tests multiple values with required delimiter
+ multiple: true
+ require_delimiter: true
+ - singlealias:
+ long: singlealias
+ help: Tests single alias
+ aliases: [alias]
+ required_if:
+ - [multvalsmo, two]
+ - multaliases:
+ long: multaliases
+ help: Tests multiple aliases
+ aliases: [als1, als2, als3]
+ - minvals2:
+ long: minvals2
+ multiple: true
+ help: Tests 2 min vals
+ min_values: 2
+ - maxvals3:
+ long: maxvals3
+ multiple: true
+ help: Tests 3 max vals
+ max_values: 3
+ - case_insensitive:
+ help: Test case_insensitive
+ possible_values: [test123, test321]
+ case_insensitive: true
+
+arg_groups:
+ - test:
+ args:
+ - maxvals3
+ - minmals2
+ conflicts_with:
+ - option3
+ requires:
+ - multvals
+subcommands:
+ - subcmd:
+ about: tests subcommands
+ version: "0.1"
+ author: Kevin K. <kbknapp@gmail.com>
+ args:
+ - scoption:
+ short: o
+ long: option
+ multiple: true
+ help: tests options
+ takes_value: true
+ - scpositional:
+ help: tests positionals
+ index: 1
diff --git a/clap/tests/app_settings.rs b/clap/tests/app_settings.rs
new file mode 100644
index 0000000..3d72a3b
--- /dev/null
+++ b/clap/tests/app_settings.rs
@@ -0,0 +1,965 @@
+extern crate clap;
+extern crate regex;
+
+use clap::{App, Arg, SubCommand, AppSettings, ErrorKind};
+
+include!("../clap-test.rs");
+
+static ALLOW_EXT_SC: &'static str = "clap-test v1.4.8
+
+USAGE:
+ clap-test [SUBCOMMAND]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information";
+
+static DONT_COLLAPSE_ARGS: &'static str = "clap-test v1.4.8
+
+USAGE:
+ clap-test [arg1] [arg2] [arg3]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ <arg1> some
+ <arg2> some
+ <arg3> some";
+
+static REQUIRE_EQUALS: &'static str = "clap-test v1.4.8
+
+USAGE:
+ clap-test --opt=<FILE>
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --opt=<FILE> some";
+
+static UNIFIED_HELP: &'static str = "test 1.3
+Kevin K.
+tests stuff
+
+USAGE:
+ test [OPTIONS] [arg1]
+
+OPTIONS:
+ -f, --flag some flag
+ -h, --help Prints help information
+ --option <opt> some option
+ -V, --version Prints version information
+
+ARGS:
+ <arg1> some pos arg";
+
+static SKIP_POS_VALS: &'static str = "test 1.3
+Kevin K.
+tests stuff
+
+USAGE:
+ test [OPTIONS] [arg1]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --opt <opt> some option
+
+ARGS:
+ <arg1> some pos arg";
+
+#[test]
+fn sub_command_negate_required() {
+ App::new("sub_command_negate")
+ .setting(AppSettings::SubcommandsNegateReqs)
+ .arg(Arg::with_name("test")
+ .required(true)
+ .index(1))
+ .subcommand(SubCommand::with_name("sub1"))
+ .get_matches_from(vec!["myprog", "sub1"]);
+}
+
+#[test]
+fn global_version() {
+ let mut app = App::new("global_version")
+ .setting(AppSettings::GlobalVersion)
+ .version("1.1")
+ .subcommand(SubCommand::with_name("sub1"));
+ app.p.propagate_settings();
+ assert_eq!(app.p.subcommands[0].p.meta.version, Some("1.1"));
+}
+
+#[test]
+fn sub_command_negate_required_2() {
+ let result = App::new("sub_command_negate")
+ .setting(AppSettings::SubcommandsNegateReqs)
+ .arg(Arg::with_name("test")
+ .required(true)
+ .index(1))
+ .subcommand(SubCommand::with_name("sub1"))
+ .get_matches_from_safe(vec![""]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn sub_command_required() {
+ let result = App::new("sc_required")
+ .setting(AppSettings::SubcommandRequired)
+ .subcommand(SubCommand::with_name("sub1"))
+ .get_matches_from_safe(vec![""]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingSubcommand);
+}
+
+#[test]
+fn arg_required_else_help() {
+ let result = App::new("arg_required")
+ .setting(AppSettings::ArgRequiredElseHelp)
+ .arg(Arg::with_name("test")
+ .index(1))
+ .get_matches_from_safe(vec![""]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingArgumentOrSubcommand);
+}
+
+#[test]
+fn arg_required_else_help_over_reqs() {
+ let result = App::new("arg_required")
+ .setting(AppSettings::ArgRequiredElseHelp)
+ .arg(Arg::with_name("test")
+ .index(1).required(true))
+ .get_matches_from_safe(vec![""]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingArgumentOrSubcommand);
+}
+
+#[cfg(not(feature = "suggestions"))]
+#[test]
+fn infer_subcommands_fail_no_args() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .subcommand(SubCommand::with_name("test"))
+ .subcommand(SubCommand::with_name("temp"))
+ .get_matches_from_safe(vec![
+ "prog", "te"
+ ]);
+ assert!(m.is_err(), "{:#?}", m.unwrap());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand);
+}
+
+#[cfg(feature = "suggestions")]
+#[test]
+fn infer_subcommands_fail_no_args() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .subcommand(SubCommand::with_name("test"))
+ .subcommand(SubCommand::with_name("temp"))
+ .get_matches_from_safe(vec![
+ "prog", "te"
+ ]);
+ assert!(m.is_err(), "{:#?}", m.unwrap());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidSubcommand);
+}
+
+#[test]
+fn infer_subcommands_fail_with_args() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .arg(Arg::with_name("some"))
+ .subcommand(SubCommand::with_name("test"))
+ .subcommand(SubCommand::with_name("temp"))
+ .get_matches_from_safe(vec![
+ "prog", "t"
+ ]);
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ assert_eq!(m.unwrap().value_of("some"), Some("t"));
+}
+
+#[test]
+fn infer_subcommands_fail_with_args2() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .arg(Arg::with_name("some"))
+ .subcommand(SubCommand::with_name("test"))
+ .subcommand(SubCommand::with_name("temp"))
+ .get_matches_from_safe(vec![
+ "prog", "te"
+ ]);
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ assert_eq!(m.unwrap().value_of("some"), Some("te"));
+}
+
+#[test]
+fn infer_subcommands_pass() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .subcommand(SubCommand::with_name("test"))
+ .get_matches_from(vec![
+ "prog", "te"
+ ]);
+ assert_eq!(m.subcommand_name(), Some("test"));
+}
+
+#[test]
+fn infer_subcommands_pass_close() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .subcommand(SubCommand::with_name("test"))
+ .subcommand(SubCommand::with_name("temp"))
+ .get_matches_from(vec![
+ "prog", "tes"
+ ]);
+ assert_eq!(m.subcommand_name(), Some("test"));
+}
+
+#[test]
+fn infer_subcommands_pass_exact_match() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .subcommand(SubCommand::with_name("test"))
+ .subcommand(SubCommand::with_name("testa"))
+ .subcommand(SubCommand::with_name("testb"))
+ .get_matches_from(vec![
+ "prog", "test"
+ ]);
+ assert_eq!(m.subcommand_name(), Some("test"));
+}
+
+#[cfg(feature = "suggestions")]
+#[test]
+fn infer_subcommands_fail_suggestions() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .subcommand(SubCommand::with_name("test"))
+ .subcommand(SubCommand::with_name("temp"))
+ .get_matches_from_safe(vec![
+ "prog", "temps"
+ ]);
+ assert!(m.is_err(), "{:#?}", m.unwrap());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidSubcommand);
+}
+
+#[cfg(not(feature = "suggestions"))]
+#[test]
+fn infer_subcommands_fail_suggestions() {
+ let m = App::new("prog")
+ .setting(AppSettings::InferSubcommands)
+ .subcommand(SubCommand::with_name("test"))
+ .subcommand(SubCommand::with_name("temp"))
+ .get_matches_from_safe(vec![
+ "prog", "temps"
+ ]);
+ assert!(m.is_err(), "{:#?}", m.unwrap());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand);
+}
+
+#[test]
+fn no_bin_name() {
+ let result = App::new("arg_required")
+ .setting(AppSettings::NoBinaryName)
+ .arg(Arg::with_name("test")
+ .required(true)
+ .index(1))
+ .get_matches_from_safe(vec!["testing"]);
+ assert!(result.is_ok());
+ let matches = result.unwrap();
+ assert_eq!(matches.value_of("test").unwrap(), "testing");
+}
+
+#[test]
+fn unified_help() {
+ let app = App::new("myTest")
+ .name("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.3")
+ .setting(AppSettings::UnifiedHelpMessage)
+ .args_from_usage("-f, --flag 'some flag'
+ [arg1] 'some pos arg'
+ --option [opt] 'some option'");
+
+ assert!(test::compare_output(app, "test --help", UNIFIED_HELP, false));
+}
+
+#[test]
+fn skip_possible_values() {
+ let app = App::new("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.3")
+ .setting(AppSettings::HidePossibleValuesInHelp)
+ .args(&[Arg::from_usage("-o, --opt [opt] 'some option'").possible_values(&["one", "two"]),
+ Arg::from_usage("[arg1] 'some pos arg'").possible_values(&["three", "four"])]);
+
+ assert!(test::compare_output(app, "test --help", SKIP_POS_VALS, false));
+}
+
+#[test]
+fn global_setting() {
+ let mut app = App::new("test")
+ .global_setting(AppSettings::ColoredHelp)
+ .subcommand(SubCommand::with_name("subcmd"));
+ app.p.propagate_settings();
+ assert!(app.p
+ .subcommands
+ .iter()
+ .filter(|s| s.p
+ .meta
+ .name == "subcmd")
+ .next()
+ .unwrap()
+ .p
+ .is_set(AppSettings::ColoredHelp));
+}
+
+#[test]
+fn global_settings() {
+ let mut app = App::new("test")
+ .global_settings(&[AppSettings::ColoredHelp, AppSettings::TrailingVarArg])
+ .subcommand(SubCommand::with_name("subcmd"));
+ app.p.propagate_settings();
+ assert!(app.p
+ .subcommands
+ .iter()
+ .filter(|s| s.p
+ .meta
+ .name == "subcmd")
+ .next()
+ .unwrap()
+ .p
+ .is_set(AppSettings::ColoredHelp));
+ assert!(app.p
+ .subcommands
+ .iter()
+ .filter(|s| s.p
+ .meta
+ .name == "subcmd")
+ .next()
+ .unwrap()
+ .p
+ .is_set(AppSettings::TrailingVarArg));
+
+}
+
+#[test]
+fn stop_delim_values_only_pos_follows() {
+ let r = App::new("onlypos")
+ .setting(AppSettings::DontDelimitTrailingValues)
+ .args(&[Arg::from_usage("-f [flag] 'some opt'"),
+ Arg::from_usage("[arg]... 'some arg'")])
+ .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert!(!m.is_present("f"));
+ assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]);
+}
+
+#[test]
+fn dont_delim_values_trailingvararg() {
+ let m = App::new("positional")
+ .setting(AppSettings::TrailingVarArg)
+ .setting(AppSettings::DontDelimitTrailingValues)
+ .arg(
+ Arg::from_usage("[opt]... 'some pos'"),
+ )
+ .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
+ assert!(m.is_present("opt"));
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]);
+}
+
+#[test]
+fn delim_values_only_pos_follows() {
+ let r = App::new("onlypos")
+ .args(&[Arg::from_usage("-f [flag] 'some opt'"),
+ Arg::from_usage("[arg]... 'some arg'")])
+ .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert!(!m.is_present("f"));
+ assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]);
+}
+
+#[test]
+fn delim_values_trailingvararg() {
+ let m = App::new("positional")
+ .setting(AppSettings::TrailingVarArg)
+ .arg(
+ Arg::from_usage("[opt]... 'some pos'"),
+ )
+ .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
+ assert!(m.is_present("opt"));
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]);
+}
+
+#[test]
+fn delim_values_only_pos_follows_with_delim() {
+ let r = App::new("onlypos")
+ .args(&[Arg::from_usage("-f [flag] 'some opt'"),
+ Arg::from_usage("[arg]... 'some arg'").use_delimiter(true)])
+ .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert!(!m.is_present("f"));
+ assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g", "x"]);
+}
+
+#[test]
+fn delim_values_trailingvararg_with_delim() {
+ let m = App::new("positional")
+ .setting(AppSettings::TrailingVarArg)
+ .arg(
+ Arg::from_usage("[opt]... 'some pos'").use_delimiter(true),
+ )
+ .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
+ assert!(m.is_present("opt"));
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl", "-bar"]);
+}
+
+#[test]
+fn leading_hyphen_short() {
+ let res = App::new("leadhy")
+ .setting(AppSettings::AllowLeadingHyphen)
+ .arg(Arg::with_name("some"))
+ .arg(Arg::with_name("other")
+ .short("o"))
+ .get_matches_from_safe(vec!["", "-bar", "-o"]);
+ assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind);
+ let m = res.unwrap();
+ assert!(m.is_present("some"));
+ assert!(m.is_present("other"));
+ assert_eq!(m.value_of("some").unwrap(), "-bar");
+}
+
+#[test]
+fn leading_hyphen_long() {
+ let res = App::new("leadhy")
+ .setting(AppSettings::AllowLeadingHyphen)
+ .arg(Arg::with_name("some"))
+ .arg(Arg::with_name("other")
+ .short("o"))
+ .get_matches_from_safe(vec!["", "--bar", "-o"]);
+ assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind);
+ let m = res.unwrap();
+ assert!(m.is_present("some"));
+ assert!(m.is_present("other"));
+ assert_eq!(m.value_of("some").unwrap(), "--bar");
+}
+
+#[test]
+fn leading_hyphen_opt() {
+ let res = App::new("leadhy")
+ .setting(AppSettings::AllowLeadingHyphen)
+ .arg(Arg::with_name("some")
+ .takes_value(true)
+ .long("opt"))
+ .arg(Arg::with_name("other")
+ .short("o"))
+ .get_matches_from_safe(vec!["", "--opt", "--bar", "-o"]);
+ assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind);
+ let m = res.unwrap();
+ assert!(m.is_present("some"));
+ assert!(m.is_present("other"));
+ assert_eq!(m.value_of("some").unwrap(), "--bar");
+}
+
+#[test]
+fn allow_negative_numbers() {
+ let res = App::new("negnum")
+ .setting(AppSettings::AllowNegativeNumbers)
+ .arg(Arg::with_name("panum"))
+ .arg(Arg::with_name("onum")
+ .short("o")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["negnum", "-20", "-o", "-1.2"]);
+ assert!(res.is_ok(), "Error: {:?}", res.unwrap_err().kind);
+ let m = res.unwrap();
+ assert_eq!(m.value_of("panum").unwrap(), "-20");
+ assert_eq!(m.value_of("onum").unwrap(), "-1.2");
+}
+
+#[test]
+fn allow_negative_numbers_fail() {
+ let res = App::new("negnum")
+ .setting(AppSettings::AllowNegativeNumbers)
+ .arg(Arg::with_name("panum"))
+ .arg(Arg::with_name("onum")
+ .short("o")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["negnum", "--foo", "-o", "-1.2"]);
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument)
+}
+
+#[test]
+fn leading_double_hyphen_trailingvararg() {
+ let m = App::new("positional")
+ .setting(AppSettings::TrailingVarArg)
+ .setting(AppSettings::AllowLeadingHyphen)
+ .arg(
+ Arg::from_usage("[opt]... 'some pos'"),
+ )
+ .get_matches_from(vec!["", "--foo", "-Wl", "bar"]);
+ assert!(m.is_present("opt"));
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["--foo", "-Wl", "bar"]);
+}
+
+#[test]
+fn test_unset_setting() {
+ let m = App::new("unset_setting");
+ assert!(m.p.is_set(AppSettings::AllowInvalidUtf8));
+
+ let m = m.unset_setting(AppSettings::AllowInvalidUtf8);
+ assert!(!m.p.is_set(AppSettings::AllowInvalidUtf8));
+}
+
+#[test]
+fn test_unset_settings() {
+ let m = App::new("unset_settings");
+ assert!(&m.p.is_set(AppSettings::AllowInvalidUtf8));
+ assert!(&m.p.is_set(AppSettings::ColorAuto));
+
+ let m = m.unset_settings(&[AppSettings::AllowInvalidUtf8,
+ AppSettings::ColorAuto]);
+ assert!(!m.p.is_set(AppSettings::AllowInvalidUtf8));
+ assert!(!m.p.is_set(AppSettings::ColorAuto));
+}
+
+#[test]
+fn disable_help_subcommand() {
+ let result = App::new("disablehelp")
+ .setting(AppSettings::DisableHelpSubcommand)
+ .subcommand(SubCommand::with_name("sub1"))
+ .get_matches_from_safe(vec!["", "help"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn dont_collapse_args() {
+ let app = App::new("clap-test")
+ .version("v1.4.8")
+ .setting(AppSettings::DontCollapseArgsInUsage)
+ .args(&[
+ Arg::with_name("arg1").help("some"),
+ Arg::with_name("arg2").help("some"),
+ Arg::with_name("arg3").help("some"),
+ ]);
+ assert!(test::compare_output(app, "clap-test --help", DONT_COLLAPSE_ARGS, false));
+}
+
+#[test]
+fn require_eq() {
+ let app = App::new("clap-test")
+ .version("v1.4.8")
+ .arg(
+ Arg::with_name("opt")
+ .long("opt")
+ .short("o")
+ .required(true)
+ .require_equals(true)
+ .value_name("FILE")
+ .help("some"),
+ );
+ assert!(test::compare_output(app, "clap-test --help", REQUIRE_EQUALS, false));
+}
+
+#[test]
+fn args_negate_subcommands_one_level() {
+ let res = App::new("disablehelp")
+ .setting(AppSettings::ArgsNegateSubcommands)
+ .setting(AppSettings::SubcommandsNegateReqs)
+ .arg_from_usage("<arg1> 'some arg'")
+ .arg_from_usage("<arg2> 'some arg'")
+ .subcommand(SubCommand::with_name("sub1")
+ .subcommand(SubCommand::with_name("sub2")
+ .subcommand(SubCommand::with_name("sub3"))
+ )
+ )
+ .get_matches_from_safe(vec!["", "pickles", "sub1"]);
+ assert!(res.is_ok(), "error: {:?}", res.unwrap_err().kind);
+ let m = res.unwrap();
+ assert_eq!(m.value_of("arg2"), Some("sub1"));
+}
+
+#[test]
+fn args_negate_subcommands_two_levels() {
+ let res = App::new("disablehelp")
+ .global_setting(AppSettings::ArgsNegateSubcommands)
+ .global_setting(AppSettings::SubcommandsNegateReqs)
+ .arg_from_usage("<arg1> 'some arg'")
+ .arg_from_usage("<arg2> 'some arg'")
+ .subcommand(SubCommand::with_name("sub1")
+ .arg_from_usage("<arg> 'some'")
+ .arg_from_usage("<arg2> 'some'")
+ .subcommand(SubCommand::with_name("sub2")
+ .subcommand(SubCommand::with_name("sub3"))
+ )
+ )
+ .get_matches_from_safe(vec!["", "sub1", "arg", "sub2"]);
+ assert!(res.is_ok(), "error: {:?}", res.unwrap_err().kind);
+ let m = res.unwrap();
+ assert_eq!(m.subcommand_matches("sub1").unwrap().value_of("arg2"), Some("sub2"));
+}
+
+
+#[test]
+fn propagate_vals_down() {
+ let m = App::new("myprog")
+ .arg(Arg::from_usage("[cmd] 'command to run'").global(true))
+ .subcommand(SubCommand::with_name("foo"))
+ .get_matches_from_safe(vec!["myprog", "set", "foo"]);
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+ assert_eq!(m.value_of("cmd"), Some("set"));
+ let sub_m = m.subcommand_matches("foo").unwrap();
+ assert_eq!(sub_m.value_of("cmd"), Some("set"));
+}
+
+#[test]
+fn allow_missing_positional() {
+ let m = App::new("test")
+ .setting(AppSettings::AllowMissingPositional)
+ .arg(Arg::from_usage("[src] 'some file'").default_value("src"))
+ .arg_from_usage("<dest> 'some file'")
+ .get_matches_from_safe(vec!["test", "file"]);
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+ assert_eq!(m.value_of("src"), Some("src"));
+ assert_eq!(m.value_of("dest"), Some("file"));
+}
+
+#[test]
+fn allow_missing_positional_no_default() {
+ let m = App::new("test")
+ .setting(AppSettings::AllowMissingPositional)
+ .arg(Arg::from_usage("[src] 'some file'"))
+ .arg_from_usage("<dest> 'some file'")
+ .get_matches_from_safe(vec!["test", "file"]);
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+ assert_eq!(m.value_of("src"), None);
+ assert_eq!(m.value_of("dest"), Some("file"));
+}
+
+#[test]
+fn missing_positional_no_hyphen() {
+ let r = App::new("bench")
+ .setting(AppSettings::AllowMissingPositional)
+ .arg(Arg::from_usage("[BENCH] 'some bench'"))
+ .arg(Arg::from_usage("[ARGS]... 'some args'"))
+ .get_matches_from_safe(vec!["bench", "foo", "arg1", "arg2", "arg3"]);
+ assert!(r.is_ok(), "{:?}", r.unwrap_err().kind);
+
+ let m = r.unwrap();
+
+ let expected_bench = Some("foo");
+ let expected_args = vec!["arg1", "arg2", "arg3"];
+
+ assert_eq!(m.value_of("BENCH"), expected_bench);
+ assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args);
+}
+
+#[test]
+fn missing_positional_hyphen() {
+ let r = App::new("bench")
+ .setting(AppSettings::AllowMissingPositional)
+ .arg(Arg::from_usage("[BENCH] 'some bench'"))
+ .arg(Arg::from_usage("[ARGS]... 'some args'"))
+ .get_matches_from_safe(vec!["bench", "--", "arg1", "arg2", "arg3"]);
+ assert!(r.is_ok(), "{:?}", r.unwrap_err().kind);
+
+ let m = r.unwrap();
+
+ let expected_bench = None;
+ let expected_args = vec!["arg1", "arg2", "arg3"];
+
+ assert_eq!(m.value_of("BENCH"), expected_bench);
+ assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args);
+}
+
+#[test]
+fn missing_positional_hyphen_far_back() {
+ let r = App::new("bench")
+ .setting(AppSettings::AllowMissingPositional)
+ .arg(Arg::from_usage("[BENCH1] 'some bench'"))
+ .arg(Arg::from_usage("[BENCH2] 'some bench'"))
+ .arg(Arg::from_usage("[BENCH3] 'some bench'"))
+ .arg(Arg::from_usage("[ARGS]... 'some args'"))
+ .get_matches_from_safe(vec!["bench", "foo", "--", "arg1", "arg2", "arg3"]);
+ assert!(r.is_ok(), "{:?}", r.unwrap_err().kind);
+
+ let m = r.unwrap();
+
+ let expected_bench1 = Some("foo");
+ let expected_bench2 = None;
+ let expected_bench3 = None;
+ let expected_args = vec!["arg1", "arg2", "arg3"];
+
+ assert_eq!(m.value_of("BENCH1"), expected_bench1);
+ assert_eq!(m.value_of("BENCH2"), expected_bench2);
+ assert_eq!(m.value_of("BENCH3"), expected_bench3);
+ assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &*expected_args);
+}
+
+#[test]
+fn missing_positional_hyphen_req_error() {
+ let r = App::new("bench")
+ .setting(AppSettings::AllowMissingPositional)
+ .arg(Arg::from_usage("[BENCH1] 'some bench'"))
+ .arg(Arg::from_usage("<BENCH2> 'some bench'"))
+ .arg(Arg::from_usage("[ARGS]... 'some args'"))
+ .get_matches_from_safe(vec!["bench", "foo", "--", "arg1", "arg2", "arg3"]);
+ assert!(r.is_err());
+ assert_eq!(r.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn issue_1066_allow_leading_hyphen_and_unknown_args() {
+ let res = App::new("prog")
+ .global_setting(AppSettings::AllowLeadingHyphen)
+ .arg(Arg::from_usage("--some-argument"))
+ .get_matches_from_safe(vec!["prog", "hello"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn issue_1066_allow_leading_hyphen_and_unknown_args_no_vals() {
+ let res = App::new("prog")
+ .global_setting(AppSettings::AllowLeadingHyphen)
+ .arg(Arg::from_usage("--some-argument"))
+ .get_matches_from_safe(vec!["prog", "--hello"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn issue_1066_allow_leading_hyphen_and_unknown_args_option() {
+ let res = App::new("prog")
+ .global_setting(AppSettings::AllowLeadingHyphen)
+ .arg(Arg::from_usage("--some-argument=[val]"))
+ .get_matches_from_safe(vec!["prog", "-hello"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn issue_1093_allow_ext_sc() {
+ let app = App::new("clap-test")
+ .version("v1.4.8")
+ .setting(AppSettings::AllowExternalSubcommands);
+ assert!(test::compare_output(app, "clap-test --help", ALLOW_EXT_SC, false));
+}
+
+
+#[test]
+fn allow_ext_sc_when_sc_required() {
+ let res = App::new("clap-test")
+ .version("v1.4.8")
+ .setting(AppSettings::AllowExternalSubcommands)
+ .setting(AppSettings::SubcommandRequiredElseHelp)
+ .get_matches_from_safe(vec!["clap-test", "external-cmd", "foo"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ match m.subcommand() {
+ (name, Some(args)) => {
+ assert_eq!(name, "external-cmd");
+ assert_eq!(args.values_of_lossy(""), Some(vec!["foo".to_string()]));
+ }
+ _ => assert!(false),
+ }
+}
+
+#[test]
+fn external_subcommand_looks_like_built_in() {
+ let res = App::new("cargo")
+ .version("1.26.0")
+ .setting(AppSettings::AllowExternalSubcommands)
+ .subcommand(SubCommand::with_name("install"))
+ .get_matches_from_safe(vec!["cargo", "install-update", "foo"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ match m.subcommand() {
+ (name, Some(args)) => {
+ assert_eq!(name, "install-update");
+ assert_eq!(args.values_of_lossy(""), Some(vec!["foo".to_string()]));
+ }
+ _ => assert!(false),
+ }
+}
+
+#[test]
+fn aaos_flags() {
+ // flags
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--flag 'some flag'"))
+ .get_matches_from_safe(vec!["", "--flag", "--flag"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("flag"));
+ assert_eq!(m.occurrences_of("flag"), 1);
+}
+
+#[test]
+fn aaos_flags_mult() {
+ // flags with multiple
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--flag... 'some flag'"))
+ .get_matches_from_safe(vec!["", "--flag", "--flag", "--flag", "--flag"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("flag"));
+ assert_eq!(m.occurrences_of("flag"), 4);
+}
+
+#[test]
+fn aaos_opts() {
+ // opts
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--opt [val] 'some option'"))
+ .get_matches_from_safe(vec!["", "--opt=some", "--opt=other"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.occurrences_of("opt"), 1);
+ assert_eq!(m.value_of("opt"), Some("other"));
+}
+
+#[test]
+fn aaos_opts_w_other_overrides() {
+ // opts with other overrides
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--opt [val] 'some option'"))
+ .arg(Arg::from_usage("--other [val] 'some other option'").overrides_with("opt"))
+ .get_matches_from_safe(vec!["", "--opt=some", "--other=test", "--opt=other"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("opt"));
+ assert!(!m.is_present("other"));
+ assert_eq!(m.occurrences_of("opt"), 1);
+ assert_eq!(m.value_of("opt"), Some("other"));
+}
+
+#[test]
+fn aaos_opts_w_other_overrides_rev() {
+ // opts with other overrides, rev
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--opt [val] 'some option'"))
+ .arg(Arg::from_usage("--other [val] 'some other option'").overrides_with("opt"))
+ .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--other=val"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(!m.is_present("opt"));
+ assert!(m.is_present("other"));
+ assert_eq!(m.value_of("other"), Some("val"));
+}
+
+#[test]
+fn aaos_opts_w_other_overrides_2() {
+ // opts with other overrides
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("other"))
+ .arg(Arg::from_usage("--other [val] 'some other option'"))
+ .get_matches_from_safe(vec!["", "--opt=some", "--other=test", "--opt=other"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("opt"));
+ assert!(!m.is_present("other"));
+ assert_eq!(m.occurrences_of("opt"), 1);
+ assert_eq!(m.value_of("opt"), Some("other"));
+}
+
+#[test]
+fn aaos_opts_w_other_overrides_rev_2() {
+ // opts with other overrides, rev
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("other"))
+ .arg(Arg::from_usage("--other [val] 'some other option'"))
+ .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--other=val"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(!m.is_present("opt"));
+ assert!(m.is_present("other"));
+ assert_eq!(m.value_of("other"), Some("val"));
+}
+
+#[test]
+fn aaos_opts_mult() {
+ // opts with multiple
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--opt [val]... 'some option'")
+ .number_of_values(1)
+ .require_delimiter(true))
+ .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.occurrences_of("opt"), 3);
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["some", "other", "one", "two"]);
+}
+
+#[test]
+fn aaos_opts_mult_req_delims() {
+ // opts with multiple and require delims
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--opt [val]... 'some option'"))
+ .get_matches_from_safe(vec!["", "--opt", "first", "overides", "--opt", "some", "other", "val"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.occurrences_of("opt"), 2);
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["first", "overides", "some", "other", "val"]);
+}
+
+#[test]
+fn aaos_pos_mult() {
+ // opts with multiple
+ let res = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("[val]... 'some pos'"))
+ .get_matches_from_safe(vec!["", "some", "other", "value"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("val"));
+ assert_eq!(m.occurrences_of("val"), 3);
+ assert_eq!(m.values_of("val").unwrap().collect::<Vec<_>>(), &["some", "other", "value"]);
+}
+
+#[test]
+fn aaos_option_use_delim_false() {
+
+ let m = App::new("posix")
+ .setting(AppSettings::AllArgsOverrideSelf)
+ .arg(Arg::from_usage("--opt [val] 'some option'")
+ .use_delimiter(false))
+ .get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]);
+ assert!(m.is_present("opt"));
+ assert_eq!(m.occurrences_of("opt"), 1);
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["one,two"]);
+}
diff --git a/clap/tests/arg_aliases.rs b/clap/tests/arg_aliases.rs
new file mode 100644
index 0000000..77bcd17
--- /dev/null
+++ b/clap/tests/arg_aliases.rs
@@ -0,0 +1,200 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, Arg, SubCommand};
+
+static SC_VISIBLE_ALIAS_HELP: &'static str = "ct-test 1.2
+Some help
+
+USAGE:
+ ct test [FLAGS] [OPTIONS]
+
+FLAGS:
+ -f, --flag [aliases: v_flg, flag2, flg3]
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --opt <opt> [aliases: visible]";
+
+static SC_INVISIBLE_ALIAS_HELP: &'static str = "ct-test 1.2
+Some help
+
+USAGE:
+ ct test [FLAGS] [OPTIONS]
+
+FLAGS:
+ -f, --flag
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --opt <opt> ";
+
+#[test]
+fn single_alias_of_option() {
+ let a = App::new("single_alias")
+ .arg(Arg::with_name("alias")
+ .long("alias")
+ .takes_value(true)
+ .help("single alias")
+ .alias("new-opt"))
+ .get_matches_from_safe(vec![
+ "", "--new-opt", "cool"
+ ]);
+ assert!(a.is_ok());
+ let a = a.unwrap();
+ assert!(a.is_present("alias"));
+ assert_eq!(a.value_of("alias").unwrap(), "cool");
+}
+
+#[test]
+fn multiple_aliases_of_option() {
+ let a = App::new("multiple_aliases")
+ .arg(Arg::with_name("aliases")
+ .long("aliases")
+ .takes_value(true)
+ .help("multiple aliases")
+ .aliases(&[
+ "alias1",
+ "alias2",
+ "alias3"
+ ]));
+ let long = a.clone().get_matches_from_safe(vec![
+ "", "--aliases", "value"
+ ]);
+ assert!(long.is_ok());
+ let long = long.unwrap();
+
+ let als1 = a.clone().get_matches_from_safe(vec![
+ "", "--alias1", "value"
+ ]);
+ assert!(als1.is_ok());
+ let als1 = als1.unwrap();
+
+ let als2 = a.clone().get_matches_from_safe(vec![
+ "", "--alias2", "value"
+ ]);
+ assert!(als2.is_ok());
+ let als2 = als2.unwrap();
+
+ let als3 = a.clone().get_matches_from_safe(vec![
+ "", "--alias3", "value"
+ ]);
+ assert!(als3.is_ok());
+ let als3 = als3.unwrap();
+
+ assert!(long.is_present("aliases"));
+ assert!(als1.is_present("aliases"));
+ assert!(als2.is_present("aliases"));
+ assert!(als3.is_present("aliases"));
+ assert_eq!(long.value_of("aliases").unwrap(), "value");
+ assert_eq!(als1.value_of("aliases").unwrap(), "value");
+ assert_eq!(als2.value_of("aliases").unwrap(), "value");
+ assert_eq!(als3.value_of("aliases").unwrap(), "value");
+}
+
+#[test]
+fn single_alias_of_flag() {
+ let a = App::new("test")
+ .arg(Arg::with_name("flag")
+ .long("flag")
+ .alias("alias"))
+ .get_matches_from_safe(vec!["", "--alias"]);
+ assert!(a.is_ok());
+ let a = a.unwrap();
+ assert!(a.is_present("flag"));
+}
+
+#[test]
+fn multiple_aliases_of_flag() {
+ let a = App::new("test")
+ .arg(Arg::with_name("flag")
+ .long("flag")
+ .aliases(&["invisible",
+ "set", "of",
+ "cool", "aliases"]));
+
+ let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]);
+ assert!(flag.is_ok());
+ let flag = flag.unwrap();
+
+ let inv = a.clone().get_matches_from_safe(vec!["", "--invisible"]);
+ assert!(inv.is_ok());
+ let inv = inv.unwrap();
+
+ let cool = a.clone().get_matches_from_safe(vec!["", "--cool"]);
+ assert!(cool.is_ok());
+ let cool = cool.unwrap();
+
+ let als = a.clone().get_matches_from_safe(vec!["", "--aliases"]);
+ assert!(als.is_ok());
+ let als = als.unwrap();
+
+ assert!(flag.is_present("flag"));
+ assert!(inv.is_present("flag"));
+ assert!(cool.is_present("flag"));
+ assert!(als.is_present("flag"));
+}
+
+#[test]
+fn alias_on_a_subcommand_option() {
+ let m = App::new("test")
+ .subcommand(SubCommand::with_name("some")
+ .arg(Arg::with_name("test")
+ .short("t")
+ .long("test")
+ .takes_value(true)
+ .alias("opt")
+ .help("testing testing")))
+ .arg(Arg::with_name("other")
+ .long("other")
+ .aliases(&["o1", "o2", "o3"]))
+ .get_matches_from(vec![
+ "test", "some", "--opt", "awesome"
+ ]);
+
+ assert!(m.subcommand_matches("some").is_some());
+ let sub_m = m.subcommand_matches("some").unwrap();
+ assert!(sub_m.is_present("test"));
+ assert_eq!(sub_m.value_of("test").unwrap(), "awesome");
+}
+
+#[test]
+fn invisible_arg_aliases_help_output() {
+ let app = App::new("ct")
+ .author("Salim Afiune")
+ .subcommand(SubCommand::with_name("test")
+ .about("Some help")
+ .version("1.2")
+ .arg(Arg::with_name("opt")
+ .long("opt")
+ .short("o")
+ .takes_value(true)
+ .aliases(&["invisible", "als1", "more"]))
+ .arg(Arg::from_usage("-f, --flag")
+ .aliases(&["invisible", "flg1", "anyway"])));
+ assert!(test::compare_output(app, "ct test --help", SC_INVISIBLE_ALIAS_HELP, false));
+}
+
+#[test]
+fn visible_arg_aliases_help_output() {
+ let app = App::new("ct")
+ .author("Salim Afiune")
+ .subcommand(SubCommand::with_name("test")
+ .about("Some help")
+ .version("1.2")
+ .arg(Arg::with_name("opt")
+ .long("opt")
+ .short("o")
+ .takes_value(true)
+ .alias("invisible")
+ .visible_alias("visible"))
+ .arg(Arg::with_name("flg")
+ .long("flag")
+ .short("f")
+ .visible_aliases(&["v_flg", "flag2", "flg3"])));
+ assert!(test::compare_output(app, "ct test --help", SC_VISIBLE_ALIAS_HELP, false));
+}
diff --git a/clap/tests/borrowed.rs b/clap/tests/borrowed.rs
new file mode 100644
index 0000000..e7a184b
--- /dev/null
+++ b/clap/tests/borrowed.rs
@@ -0,0 +1,19 @@
+extern crate clap;
+extern crate regex;
+
+use clap::{App, Arg, SubCommand};
+
+include!("../clap-test.rs");
+
+#[test]
+fn borrowed_args() {
+ let arg = Arg::with_name("some").short("s").long("some").help("other help");
+ let arg2 = Arg::with_name("some2").short("S").long("some-thing").help("other help");
+ let result = App::new("sub_command_negate")
+ .arg(Arg::with_name("test").index(1))
+ .arg(&arg)
+ .arg(&arg2)
+ .subcommand(SubCommand::with_name("sub1").arg(&arg))
+ .get_matches_from_safe(vec!["prog"]);
+ assert!(result.is_ok());
+}
diff --git a/clap/tests/completions.rs b/clap/tests/completions.rs
new file mode 100644
index 0000000..24409ad
--- /dev/null
+++ b/clap/tests/completions.rs
@@ -0,0 +1,883 @@
+extern crate regex;
+extern crate clap;
+
+use clap::{App, Arg, SubCommand, Shell};
+use regex::Regex;
+
+static BASH: &'static str = r#"_myapp() {
+ local i cur prev opts cmds
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ cmd=""
+ opts=""
+
+ for i in ${COMP_WORDS[@]}
+ do
+ case "${i}" in
+ myapp)
+ cmd="myapp"
+ ;;
+
+ help)
+ cmd+="__help"
+ ;;
+ test)
+ cmd+="__test"
+ ;;
+ *)
+ ;;
+ esac
+ done
+
+ case "${cmd}" in
+ myapp)
+ opts=" -h -V --help --version <file> test help"
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+
+ myapp__help)
+ opts=" -h -V --help --version "
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+ myapp__test)
+ opts=" -h -V --help --version --case "
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+
+ --case)
+ COMPREPLY=($(compgen -f "${cur}"))
+ return 0
+ ;;
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+ esac
+}
+
+complete -F _myapp -o bashdefault -o default myapp
+"#;
+
+static ZSH: &'static str = r#"#compdef myapp
+
+autoload -U is-at-least
+
+_myapp() {
+ typeset -A opt_args
+ typeset -a _arguments_options
+ local ret=1
+
+ if is-at-least 5.2; then
+ _arguments_options=(-s -S -C)
+ else
+ _arguments_options=(-s -C)
+ fi
+
+ local context curcontext="$curcontext" state line
+ _arguments "${_arguments_options[@]}" \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+'::file -- some input file:_files' \
+":: :_myapp_commands" \
+"*::: :->myapp" \
+&& ret=0
+ case $state in
+ (myapp)
+ words=($line[2] "${words[@]}")
+ (( CURRENT += 1 ))
+ curcontext="${curcontext%:*:*}:myapp-command-$line[2]:"
+ case $line[2] in
+ (test)
+_arguments "${_arguments_options[@]}" \
+'--case=[the case to test]' \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+&& ret=0
+;;
+(help)
+_arguments "${_arguments_options[@]}" \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+&& ret=0
+;;
+ esac
+ ;;
+esac
+}
+
+(( $+functions[_myapp_commands] )) ||
+_myapp_commands() {
+ local commands; commands=(
+ "test:tests things" \
+"help:Prints this message or the help of the given subcommand(s)" \
+ )
+ _describe -t commands 'myapp commands' commands "$@"
+}
+(( $+functions[_myapp__help_commands] )) ||
+_myapp__help_commands() {
+ local commands; commands=(
+
+ )
+ _describe -t commands 'myapp help commands' commands "$@"
+}
+(( $+functions[_myapp__test_commands] )) ||
+_myapp__test_commands() {
+ local commands; commands=(
+
+ )
+ _describe -t commands 'myapp test commands' commands "$@"
+}
+
+_myapp "$@""#;
+
+static FISH: &'static str = r#"complete -c myapp -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'
+complete -c myapp -n "__fish_use_subcommand" -s V -l version -d 'Prints version information'
+complete -c myapp -n "__fish_use_subcommand" -f -a "test" -d 'tests things'
+complete -c myapp -n "__fish_use_subcommand" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)'
+complete -c myapp -n "__fish_seen_subcommand_from test" -l case -d 'the case to test'
+complete -c myapp -n "__fish_seen_subcommand_from test" -s h -l help -d 'Prints help information'
+complete -c myapp -n "__fish_seen_subcommand_from test" -s V -l version -d 'Prints version information'
+complete -c myapp -n "__fish_seen_subcommand_from help" -s h -l help -d 'Prints help information'
+complete -c myapp -n "__fish_seen_subcommand_from help" -s V -l version -d 'Prints version information'
+"#;
+
+static POWERSHELL: &'static str = r#"
+using namespace System.Management.Automation
+using namespace System.Management.Automation.Language
+
+Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock {
+ param($wordToComplete, $commandAst, $cursorPosition)
+
+ $commandElements = $commandAst.CommandElements
+ $command = @(
+ 'my_app'
+ for ($i = 1; $i -lt $commandElements.Count; $i++) {
+ $element = $commandElements[$i]
+ if ($element -isnot [StringConstantExpressionAst] -or
+ $element.StringConstantType -ne [StringConstantType]::BareWord -or
+ $element.Value.StartsWith('-')) {
+ break
+ }
+ $element.Value
+ }) -join ';'
+
+ $completions = @(switch ($command) {
+ 'my_app' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'tests things')
+ [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Prints this message or the help of the given subcommand(s)')
+ break
+ }
+ 'my_app;test' {
+ [CompletionResult]::new('--case', 'case', [CompletionResultType]::ParameterName, 'the case to test')
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
+ break
+ }
+ 'my_app;help' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
+ break
+ }
+ })
+
+ $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
+ Sort-Object -Property ListItemText
+}
+"#;
+
+static ELVISH: &'static str = r#"
+edit:completion:arg-completer[my_app] = [@words]{
+ fn spaces [n]{
+ repeat $n ' ' | joins ''
+ }
+ fn cand [text desc]{
+ edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc
+ }
+ command = 'my_app'
+ for word $words[1:-1] {
+ if (has-prefix $word '-') {
+ break
+ }
+ command = $command';'$word
+ }
+ completions = [
+ &'my_app'= {
+ cand -h 'Prints help information'
+ cand --help 'Prints help information'
+ cand -V 'Prints version information'
+ cand --version 'Prints version information'
+ cand test 'tests things'
+ cand help 'Prints this message or the help of the given subcommand(s)'
+ }
+ &'my_app;test'= {
+ cand --case 'the case to test'
+ cand -h 'Prints help information'
+ cand --help 'Prints help information'
+ cand -V 'Prints version information'
+ cand --version 'Prints version information'
+ }
+ &'my_app;help'= {
+ cand -h 'Prints help information'
+ cand --help 'Prints help information'
+ cand -V 'Prints version information'
+ cand --version 'Prints version information'
+ }
+ ]
+ $completions[$command]
+}
+"#;
+
+static ELVISH_SPECIAL_CMDS: &'static str = r#"
+edit:completion:arg-completer[my_app] = [@words]{
+ fn spaces [n]{
+ repeat $n ' ' | joins ''
+ }
+ fn cand [text desc]{
+ edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc
+ }
+ command = 'my_app'
+ for word $words[1:-1] {
+ if (has-prefix $word '-') {
+ break
+ }
+ command = $command';'$word
+ }
+ completions = [
+ &'my_app'= {
+ cand -h 'Prints help information'
+ cand --help 'Prints help information'
+ cand -V 'Prints version information'
+ cand --version 'Prints version information'
+ cand test 'tests things'
+ cand some_cmd 'tests other things'
+ cand some-cmd-with-hypens 'some-cmd-with-hypens'
+ cand help 'Prints this message or the help of the given subcommand(s)'
+ }
+ &'my_app;test'= {
+ cand --case 'the case to test'
+ cand -h 'Prints help information'
+ cand --help 'Prints help information'
+ cand -V 'Prints version information'
+ cand --version 'Prints version information'
+ }
+ &'my_app;some_cmd'= {
+ cand --config 'the other case to test'
+ cand -h 'Prints help information'
+ cand --help 'Prints help information'
+ cand -V 'Prints version information'
+ cand --version 'Prints version information'
+ }
+ &'my_app;some-cmd-with-hypens'= {
+ cand -h 'Prints help information'
+ cand --help 'Prints help information'
+ cand -V 'Prints version information'
+ cand --version 'Prints version information'
+ }
+ &'my_app;help'= {
+ cand -h 'Prints help information'
+ cand --help 'Prints help information'
+ cand -V 'Prints version information'
+ cand --version 'Prints version information'
+ }
+ ]
+ $completions[$command]
+}
+"#;
+
+static POWERSHELL_SPECIAL_CMDS: &'static str = r#"
+using namespace System.Management.Automation
+using namespace System.Management.Automation.Language
+
+Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock {
+ param($wordToComplete, $commandAst, $cursorPosition)
+
+ $commandElements = $commandAst.CommandElements
+ $command = @(
+ 'my_app'
+ for ($i = 1; $i -lt $commandElements.Count; $i++) {
+ $element = $commandElements[$i]
+ if ($element -isnot [StringConstantExpressionAst] -or
+ $element.StringConstantType -ne [StringConstantType]::BareWord -or
+ $element.Value.StartsWith('-')) {
+ break
+ }
+ $element.Value
+ }) -join ';'
+
+ $completions = @(switch ($command) {
+ 'my_app' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'tests things')
+ [CompletionResult]::new('some_cmd', 'some_cmd', [CompletionResultType]::ParameterValue, 'tests other things')
+ [CompletionResult]::new('some-cmd-with-hypens', 'some-cmd-with-hypens', [CompletionResultType]::ParameterValue, 'some-cmd-with-hypens')
+ [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Prints this message or the help of the given subcommand(s)')
+ break
+ }
+ 'my_app;test' {
+ [CompletionResult]::new('--case', 'case', [CompletionResultType]::ParameterName, 'the case to test')
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
+ break
+ }
+ 'my_app;some_cmd' {
+ [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'the other case to test')
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
+ break
+ }
+ 'my_app;some-cmd-with-hypens' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
+ break
+ }
+ 'my_app;help' {
+ [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Prints help information')
+ [CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Prints version information')
+ [CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Prints version information')
+ break
+ }
+ })
+
+ $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
+ Sort-Object -Property ListItemText
+}
+"#;
+
+static ZSH_SPECIAL_CMDS: &'static str = r#"#compdef my_app
+
+autoload -U is-at-least
+
+_my_app() {
+ typeset -A opt_args
+ typeset -a _arguments_options
+ local ret=1
+
+ if is-at-least 5.2; then
+ _arguments_options=(-s -S -C)
+ else
+ _arguments_options=(-s -C)
+ fi
+
+ local context curcontext="$curcontext" state line
+ _arguments "${_arguments_options[@]}" \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+'::file -- some input file:_files' \
+":: :_my_app_commands" \
+"*::: :->my_app" \
+&& ret=0
+ case $state in
+ (my_app)
+ words=($line[2] "${words[@]}")
+ (( CURRENT += 1 ))
+ curcontext="${curcontext%:*:*}:my_app-command-$line[2]:"
+ case $line[2] in
+ (test)
+_arguments "${_arguments_options[@]}" \
+'--case=[the case to test]' \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+&& ret=0
+;;
+(some_cmd)
+_arguments "${_arguments_options[@]}" \
+'--config=[the other case to test]' \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+&& ret=0
+;;
+(some-cmd-with-hypens)
+_arguments "${_arguments_options[@]}" \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+&& ret=0
+;;
+(help)
+_arguments "${_arguments_options[@]}" \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+&& ret=0
+;;
+ esac
+ ;;
+esac
+}
+
+(( $+functions[_my_app_commands] )) ||
+_my_app_commands() {
+ local commands; commands=(
+ "test:tests things" \
+"some_cmd:tests other things" \
+"some-cmd-with-hypens:" \
+"help:Prints this message or the help of the given subcommand(s)" \
+ )
+ _describe -t commands 'my_app commands' commands "$@"
+}
+(( $+functions[_my_app__help_commands] )) ||
+_my_app__help_commands() {
+ local commands; commands=(
+
+ )
+ _describe -t commands 'my_app help commands' commands "$@"
+}
+(( $+functions[_my_app__some-cmd-with-hypens_commands] )) ||
+_my_app__some-cmd-with-hypens_commands() {
+ local commands; commands=(
+
+ )
+ _describe -t commands 'my_app some-cmd-with-hypens commands' commands "$@"
+}
+(( $+functions[_my_app__some_cmd_commands] )) ||
+_my_app__some_cmd_commands() {
+ local commands; commands=(
+
+ )
+ _describe -t commands 'my_app some_cmd commands' commands "$@"
+}
+(( $+functions[_my_app__test_commands] )) ||
+_my_app__test_commands() {
+ local commands; commands=(
+
+ )
+ _describe -t commands 'my_app test commands' commands "$@"
+}
+
+_my_app "$@""#;
+
+static FISH_SPECIAL_CMDS: &'static str = r#"complete -c my_app -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_use_subcommand" -s V -l version -d 'Prints version information'
+complete -c my_app -n "__fish_use_subcommand" -f -a "test" -d 'tests things'
+complete -c my_app -n "__fish_use_subcommand" -f -a "some_cmd" -d 'tests other things'
+complete -c my_app -n "__fish_use_subcommand" -f -a "some-cmd-with-hypens"
+complete -c my_app -n "__fish_use_subcommand" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)'
+complete -c my_app -n "__fish_seen_subcommand_from test" -l case -d 'the case to test'
+complete -c my_app -n "__fish_seen_subcommand_from test" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_seen_subcommand_from test" -s V -l version -d 'Prints version information'
+complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -l config -d 'the other case to test'
+complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -s V -l version -d 'Prints version information'
+complete -c my_app -n "__fish_seen_subcommand_from some-cmd-with-hypens" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_seen_subcommand_from some-cmd-with-hypens" -s V -l version -d 'Prints version information'
+complete -c my_app -n "__fish_seen_subcommand_from help" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_seen_subcommand_from help" -s V -l version -d 'Prints version information'
+"#;
+
+static BASH_SPECIAL_CMDS: &'static str = r#"_my_app() {
+ local i cur prev opts cmds
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ cmd=""
+ opts=""
+
+ for i in ${COMP_WORDS[@]}
+ do
+ case "${i}" in
+ my_app)
+ cmd="my_app"
+ ;;
+
+ help)
+ cmd+="__help"
+ ;;
+ some-cmd-with-hypens)
+ cmd+="__some__cmd__with__hypens"
+ ;;
+ some_cmd)
+ cmd+="__some_cmd"
+ ;;
+ test)
+ cmd+="__test"
+ ;;
+ *)
+ ;;
+ esac
+ done
+
+ case "${cmd}" in
+ my_app)
+ opts=" -h -V --help --version <file> test some_cmd some-cmd-with-hypens help"
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+
+ my_app__help)
+ opts=" -h -V --help --version "
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+ my_app__some__cmd__with__hypens)
+ opts=" -h -V --help --version "
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+ my_app__some_cmd)
+ opts=" -h -V --help --version --config "
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+
+ --config)
+ COMPREPLY=($(compgen -f "${cur}"))
+ return 0
+ ;;
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+ my_app__test)
+ opts=" -h -V --help --version --case "
+ if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ fi
+ case "${prev}" in
+
+ --case)
+ COMPREPLY=($(compgen -f "${cur}"))
+ return 0
+ ;;
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
+ return 0
+ ;;
+ esac
+}
+
+complete -F _my_app -o bashdefault -o default my_app
+"#;
+
+static FISH_SPECIAL_HELP: &'static str = r#"complete -c my_app -n "__fish_use_subcommand" -l single-quotes -d 'Can be \'always\', \'auto\', or \'never\''
+complete -c my_app -n "__fish_use_subcommand" -l double-quotes -d 'Can be "always", "auto", or "never"'
+complete -c my_app -n "__fish_use_subcommand" -l backticks -d 'For more information see `echo test`'
+complete -c my_app -n "__fish_use_subcommand" -l backslash -d 'Avoid \'\\n\''
+complete -c my_app -n "__fish_use_subcommand" -l brackets -d 'List packages [filter]'
+complete -c my_app -n "__fish_use_subcommand" -l expansions -d 'Execute the shell command with $SHELL'
+complete -c my_app -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_use_subcommand" -s V -l version -d 'Prints version information'
+"#;
+
+static ZSH_SPECIAL_HELP: &'static str = r#"#compdef my_app
+
+autoload -U is-at-least
+
+_my_app() {
+ typeset -A opt_args
+ typeset -a _arguments_options
+ local ret=1
+
+ if is-at-least 5.2; then
+ _arguments_options=(-s -S -C)
+ else
+ _arguments_options=(-s -C)
+ fi
+
+ local context curcontext="$curcontext" state line
+ _arguments "${_arguments_options[@]}" \
+'--single-quotes[Can be '\''always'\'', '\''auto'\'', or '\''never'\'']' \
+'--double-quotes[Can be "always", "auto", or "never"]' \
+'--backticks[For more information see `echo test`]' \
+'--backslash[Avoid '\''\\n'\'']' \
+'--brackets[List packages \[filter\]]' \
+'--expansions[Execute the shell command with $SHELL]' \
+'-h[Prints help information]' \
+'--help[Prints help information]' \
+'-V[Prints version information]' \
+'--version[Prints version information]' \
+&& ret=0
+
+}
+
+(( $+functions[_my_app_commands] )) ||
+_my_app_commands() {
+ local commands; commands=(
+
+ )
+ _describe -t commands 'my_app commands' commands "$@"
+}
+
+_my_app "$@""#;
+
+fn compare(left: &str, right: &str) -> bool {
+ let b = left == right;
+ if !b {
+ let re = Regex::new(" ").unwrap();
+ println!();
+ println!("--> left");
+ // println!("{}", left);
+ println!("{}", re.replace_all(left, "\u{2022}"));
+ println!("--> right");
+ println!("{}", re.replace_all(right, "\u{2022}"));
+ // println!("{}", right);
+ println!("--")
+ }
+ b
+}
+
+fn build_app() -> App<'static, 'static> { build_app_with_name("myapp") }
+
+fn build_app_with_name(s: &'static str) -> App<'static, 'static> {
+ App::new(s)
+ .about("Tests completions")
+ .arg(Arg::with_name("file").help("some input file"))
+ .subcommand(SubCommand::with_name("test")
+ .about("tests things")
+ .arg(Arg::with_name("case")
+ .long("case")
+ .takes_value(true)
+ .help("the case to test")))
+}
+
+fn build_app_special_commands() -> App<'static, 'static> {
+ build_app_with_name("my_app")
+ .subcommand(SubCommand::with_name("some_cmd")
+ .about("tests other things")
+ .arg(Arg::with_name("config")
+ .long("--config")
+ .takes_value(true)
+ .help("the other case to test")))
+ .subcommand(SubCommand::with_name("some-cmd-with-hypens"))
+}
+
+fn build_app_special_help() -> App<'static, 'static> {
+ App::new("my_app")
+ .arg(Arg::with_name("single-quotes")
+ .long("single-quotes")
+ .help("Can be 'always', 'auto', or 'never'"))
+ .arg(Arg::with_name("double-quotes")
+ .long("double-quotes")
+ .help("Can be \"always\", \"auto\", or \"never\""))
+ .arg(Arg::with_name("backticks")
+ .long("backticks")
+ .help("For more information see `echo test`"))
+ .arg(Arg::with_name("backslash")
+ .long("backslash")
+ .help("Avoid '\\n'"))
+ .arg(Arg::with_name("brackets")
+ .long("brackets")
+ .help("List packages [filter]"))
+ .arg(Arg::with_name("expansions")
+ .long("expansions")
+ .help("Execute the shell command with $SHELL"))
+}
+
+#[test]
+fn bash() {
+ let mut app = build_app();
+ let mut buf = vec![];
+ app.gen_completions_to("myapp", Shell::Bash, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, BASH));
+}
+
+#[test]
+fn zsh() {
+ let mut app = build_app();
+ let mut buf = vec![];
+ app.gen_completions_to("myapp", Shell::Zsh, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, ZSH));
+}
+
+#[test]
+fn fish() {
+ let mut app = build_app();
+ let mut buf = vec![];
+ app.gen_completions_to("myapp", Shell::Fish, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, FISH));
+}
+
+#[test]
+fn powershell() {
+ let mut app = build_app();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::PowerShell, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, POWERSHELL));
+}
+
+#[test]
+fn elvish() {
+ let mut app = build_app();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::Elvish, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, ELVISH));
+}
+
+#[test]
+fn elvish_with_special_commands() {
+ let mut app = build_app_special_commands();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::Elvish, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, ELVISH_SPECIAL_CMDS));
+}
+
+#[test]
+fn powershell_with_special_commands() {
+ let mut app = build_app_special_commands();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::PowerShell, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, POWERSHELL_SPECIAL_CMDS));
+}
+
+#[test]
+fn bash_with_special_commands() {
+ let mut app = build_app_special_commands();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::Bash, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, BASH_SPECIAL_CMDS));
+}
+
+#[test]
+fn fish_with_special_commands() {
+ let mut app = build_app_special_commands();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::Fish, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, FISH_SPECIAL_CMDS));
+}
+
+#[test]
+fn zsh_with_special_commands() {
+ let mut app = build_app_special_commands();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::Zsh, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, ZSH_SPECIAL_CMDS));
+}
+
+#[test]
+fn fish_with_special_help() {
+ let mut app = build_app_special_help();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::Fish, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, FISH_SPECIAL_HELP));
+}
+
+#[test]
+fn zsh_with_special_help() {
+ let mut app = build_app_special_help();
+ let mut buf = vec![];
+ app.gen_completions_to("my_app", Shell::Zsh, &mut buf);
+ let string = String::from_utf8(buf).unwrap();
+
+ assert!(compare(&*string, ZSH_SPECIAL_HELP));
+}
diff --git a/clap/tests/conflicts.rs b/clap/tests/conflicts.rs
new file mode 100644
index 0000000..72a9e05
--- /dev/null
+++ b/clap/tests/conflicts.rs
@@ -0,0 +1,102 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, Arg, ErrorKind, ArgGroup};
+
+static CONFLICT_ERR: &'static str = "error: The argument '-F' cannot be used with '--flag'
+
+USAGE:
+ clap-test <positional> <positional2> --flag --long-option-2 <option2>
+
+For more information try --help";
+
+static CONFLICT_ERR_REV: &'static str = "error: The argument '--flag' cannot be used with '-F'
+
+USAGE:
+ clap-test <positional> <positional2> -F --long-option-2 <option2>
+
+For more information try --help";
+
+#[test]
+fn flag_conflict() {
+ let result = App::new("flag_conflict")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("other"))
+ .arg(Arg::from_usage("-o, --other 'some flag'"))
+ .get_matches_from_safe(vec!["myprog", "-f", "-o"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+}
+
+#[test]
+fn flag_conflict_2() {
+ let result = App::new("flag_conflict")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("other"))
+ .arg(Arg::from_usage("-o, --other 'some flag'"))
+ .get_matches_from_safe(vec!["myprog", "-o", "-f"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+}
+
+#[test]
+fn group_conflict() {
+ let result = App::new("group_conflict")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("gr"))
+ .group(ArgGroup::with_name("gr")
+ .required(true)
+ .arg("some")
+ .arg("other"))
+ .arg(Arg::from_usage("--some 'some arg'"))
+ .arg(Arg::from_usage("--other 'other arg'"))
+ .get_matches_from_safe(vec!["myprog", "--other", "-f"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+}
+
+#[test]
+fn group_conflict_2() {
+ let result = App::new("group_conflict")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("gr"))
+ .group(ArgGroup::with_name("gr")
+ .required(true)
+ .arg("some")
+ .arg("other"))
+ .arg(Arg::from_usage("--some 'some arg'"))
+ .arg(Arg::from_usage("--other 'other arg'"))
+ .get_matches_from_safe(vec!["myprog", "-f", "--some"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+}
+
+#[test]
+fn conflict_output() {
+ test::compare_output(test::complex_app(), "clap-test val1 --flag --long-option-2 val2 -F", CONFLICT_ERR, true);
+}
+
+#[test]
+fn conflict_output_rev() {
+ test::compare_output(test::complex_app(), "clap-test val1 -F --long-option-2 val2 --flag", CONFLICT_ERR_REV, true);
+}
+
+#[test]
+fn conflict_with_unused_default_value() {
+ let result = App::new("conflict")
+ .arg(Arg::from_usage("-o, --opt=[opt] 'some opt'")
+ .default_value("default"))
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("opt"))
+ .get_matches_from_safe(vec!["myprog", "-f"]);
+ assert!(result.is_ok());
+ let m = result.unwrap();
+ assert_eq!(m.value_of("opt"), Some("default"));
+ assert!(m.is_present("flag"));
+}
diff --git a/clap/tests/default_vals.rs b/clap/tests/default_vals.rs
new file mode 100644
index 0000000..0dfd3c8
--- /dev/null
+++ b/clap/tests/default_vals.rs
@@ -0,0 +1,498 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, Arg, ErrorKind};
+
+#[test]
+fn opts() {
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("-o [opt] 'some opt'").default_value("default"),
+ )
+ .get_matches_from_safe(vec![""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.value_of("o").unwrap(), "default");
+}
+
+#[test]
+fn opt_user_override() {
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("--opt [FILE] 'some arg'").default_value("default"),
+ )
+ .get_matches_from_safe(vec!["", "--opt", "value"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.value_of("opt").unwrap(), "value");
+}
+
+#[test]
+fn positionals() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("[arg] 'some opt'").default_value("default"))
+ .get_matches_from_safe(vec![""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "default");
+}
+
+#[test]
+fn positional_user_override() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("[arg] 'some arg'").default_value("default"))
+ .get_matches_from_safe(vec!["", "value"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "value");
+}
+
+// OsStr Default Values
+
+#[test]
+fn osstr_opts() {
+ use std::ffi::OsStr;
+ let expected = OsStr::new("default");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("-o [opt] 'some opt'").default_value_os(expected),
+ )
+ .get_matches_from_safe(vec![""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.value_of("o").unwrap(), expected);
+}
+
+#[test]
+fn osstr_opt_user_override() {
+ use std::ffi::OsStr;
+ let default = OsStr::new("default");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("--opt [FILE] 'some arg'").default_value_os(default),
+ )
+ .get_matches_from_safe(vec!["", "--opt", "value"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.value_of("opt").unwrap(), "value");
+}
+
+#[test]
+fn osstr_positionals() {
+ use std::ffi::OsStr;
+ let expected = OsStr::new("default");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'").default_value_os(expected),
+ )
+ .get_matches_from_safe(vec![""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), expected);
+}
+
+#[test]
+fn osstr_positional_user_override() {
+ use std::ffi::OsStr;
+ let default = OsStr::new("default");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some arg'").default_value_os(default),
+ )
+ .get_matches_from_safe(vec!["", "value"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "value");
+}
+
+// --- Default if arg is present
+
+#[test]
+fn default_if_arg_present_no_default() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
+ "opt",
+ None,
+ "default",
+ ))
+ .get_matches_from_safe(vec!["", "--opt", "some"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "default");
+}
+
+#[test]
+fn default_if_arg_present_no_default_user_override() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
+ "opt",
+ None,
+ "default",
+ ))
+ .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "other");
+}
+
+#[test]
+fn default_if_arg_present_no_arg_with_default() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", None, "default"),
+ )
+ .get_matches_from_safe(vec![""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "first");
+}
+
+#[test]
+fn default_if_arg_present_with_default() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", None, "default"),
+ )
+ .get_matches_from_safe(vec!["", "--opt", "some"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "default");
+}
+
+#[test]
+fn default_if_arg_present_with_default_user_override() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", None, "default"),
+ )
+ .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "other");
+}
+
+#[test]
+fn default_if_arg_present_no_arg_with_default_user_override() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", None, "default"),
+ )
+ .get_matches_from_safe(vec!["", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "other");
+}
+
+// Conditional Default Values
+
+#[test]
+fn default_if_arg_present_with_value_no_default() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
+ "opt",
+ Some("value"),
+ "default",
+ ))
+ .get_matches_from_safe(vec!["", "--opt", "value"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "default");
+}
+
+#[test]
+fn default_if_arg_present_with_value_no_default_fail() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
+ "opt",
+ Some("value"),
+ "default",
+ ))
+ .get_matches_from_safe(vec!["", "--opt", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(!m.is_present("arg"));
+ //assert_eq!(m.value_of("arg").unwrap(), "default");
+}
+
+#[test]
+fn default_if_arg_present_with_value_no_default_user_override() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(Arg::from_usage("[arg] 'some arg'").default_value_if(
+ "opt",
+ Some("some"),
+ "default",
+ ))
+ .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "other");
+}
+
+#[test]
+fn default_if_arg_present_with_value_no_arg_with_default() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", Some("some"), "default"),
+ )
+ .get_matches_from_safe(vec![""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "first");
+}
+
+#[test]
+fn default_if_arg_present_with_value_no_arg_with_default_fail() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", Some("some"), "default"),
+ )
+ .get_matches_from_safe(vec!["", "--opt", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "first");
+}
+
+#[test]
+fn default_if_arg_present_with_value_with_default() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", Some("some"), "default"),
+ )
+ .get_matches_from_safe(vec!["", "--opt", "some"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "default");
+}
+
+#[test]
+fn default_if_arg_present_with_value_with_default_user_override() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", Some("some"), "default"),
+ )
+ .get_matches_from_safe(vec!["", "--opt", "some", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "other");
+}
+
+#[test]
+fn default_if_arg_present_no_arg_with_value_with_default_user_override() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", Some("some"), "default"),
+ )
+ .get_matches_from_safe(vec!["", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "other");
+}
+
+#[test]
+fn default_if_arg_present_no_arg_with_value_with_default_user_override_fail() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_if("opt", Some("some"), "default"),
+ )
+ .get_matches_from_safe(vec!["", "--opt", "value", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "other");
+}
+
+// Multiple conditions
+
+#[test]
+fn default_ifs_arg_present() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(Arg::from_usage("--flag 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]),
+ )
+ .get_matches_from_safe(vec!["", "--flag"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "flg");
+}
+
+#[test]
+fn default_ifs_arg_present_user_override() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(Arg::from_usage("--flag 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]),
+ )
+ .get_matches_from_safe(vec!["", "--flag", "value"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "value");
+}
+
+#[test]
+fn default_ifs_arg_present_order() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("--opt [FILE] 'some arg'"))
+ .arg(Arg::from_usage("--flag 'some arg'"))
+ .arg(
+ Arg::from_usage("[arg] 'some arg'")
+ .default_value("first")
+ .default_value_ifs(&[("opt", Some("some"), "default"), ("flag", None, "flg")]),
+ )
+ .get_matches_from_safe(vec!["", "--opt=some", "--flag"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.value_of("arg").unwrap(), "default");
+}
+
+#[test]
+fn conditional_reqs_fail() {
+ let m = App::new("Test app")
+ .version("1.0")
+ .author("F0x06")
+ .about("Arg test")
+ .arg(
+ Arg::with_name("target")
+ .takes_value(true)
+ .default_value("file")
+ .possible_values(&["file", "stdout"])
+ .long("target"),
+ )
+ .arg(
+ Arg::with_name("input")
+ .takes_value(true)
+ .required(true)
+ .long("input"),
+ )
+ .arg(
+ Arg::with_name("output")
+ .takes_value(true)
+ .required_if("target", "file")
+ .long("output"),
+ )
+ .get_matches_from_safe(vec!["test", "--input", "some"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn conditional_reqs_pass() {
+ let m = App::new("Test app")
+ .version("1.0")
+ .author("F0x06")
+ .about("Arg test")
+ .arg(
+ Arg::with_name("target")
+ .takes_value(true)
+ .default_value("file")
+ .possible_values(&["file", "stdout"])
+ .long("target"),
+ )
+ .arg(
+ Arg::with_name("input")
+ .takes_value(true)
+ .required(true)
+ .long("input"),
+ )
+ .arg(
+ Arg::with_name("output")
+ .takes_value(true)
+ .required_if("target", "file")
+ .long("output"),
+ )
+ .get_matches_from_safe(vec!["test", "--input", "some", "--output", "other"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+ assert_eq!(m.value_of("output"), Some("other"));
+ assert_eq!(m.value_of("input"), Some("some"));
+}
+
+#[test]
+fn issue_1050_num_vals_and_defaults() {
+ let res = App::new("hello")
+ .arg(
+ Arg::with_name("exit-code")
+ .long("exit-code")
+ .required(true)
+ .takes_value(true)
+ .number_of_values(1)
+ .default_value("0"),
+ )
+ .get_matches_from_safe(vec!["hello", "--exit-code=1"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert_eq!(m.value_of("exit-code"), Some("1"));
+}
diff --git a/clap/tests/delimiters.rs b/clap/tests/delimiters.rs
new file mode 100644
index 0000000..d5b60b9
--- /dev/null
+++ b/clap/tests/delimiters.rs
@@ -0,0 +1,139 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+#[test]
+fn opt_default_no_delim() {
+ let m = App::new("no_delim")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .takes_value(true))
+ .get_matches_from_safe(vec![
+ "",
+ "--option", "val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
+}
+
+#[test]
+fn opt_eq_no_delim() {
+ let m = App::new("no_delim")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .takes_value(true))
+ .get_matches_from_safe(vec![
+ "",
+ "--option=val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
+}
+
+#[test]
+fn opt_s_eq_no_delim() {
+ let m = App::new("no_delim")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .takes_value(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-o=val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok(), "{:?}", m.unwrap_err());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
+}
+
+#[test]
+fn opt_s_default_no_delim() {
+ let m = App::new("no_delim")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .takes_value(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok(), "{:?}", m.unwrap_err());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
+}
+
+#[test]
+fn opt_s_no_space_no_delim() {
+ let m = App::new("no_delim")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .takes_value(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
+}
+
+#[test]
+fn opt_s_no_space_mult_no_delim() {
+ let m = App::new("no_delim")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .multiple(true)
+ .takes_value(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
+}
+
+#[test]
+fn opt_eq_mult_def_delim() {
+ let m = App::new("no_delim")
+ .arg(Arg::with_name("option")
+ .long("opt")
+ .multiple(true)
+ .use_delimiter(true)
+ .takes_value(true))
+ .get_matches_from_safe(vec![
+ "",
+ "--opt=val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1", "val2", "val3"]);
+}
diff --git a/clap/tests/derive_order.rs b/clap/tests/derive_order.rs
new file mode 100644
index 0000000..b30c8ad
--- /dev/null
+++ b/clap/tests/derive_order.rs
@@ -0,0 +1,245 @@
+extern crate clap;
+extern crate regex;
+
+use std::str;
+
+use clap::{App, Arg, SubCommand, AppSettings};
+
+include!("../clap-test.rs");
+
+static NO_DERIVE_ORDER: &'static str = "test 1.2
+
+USAGE:
+ test [FLAGS] [OPTIONS]
+
+FLAGS:
+ --flag_a second flag
+ --flag_b first flag
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --option_a <option_a> second option
+ --option_b <option_b> first option";
+
+static DERIVE_ORDER: &'static str = "test 1.2
+
+USAGE:
+ test [FLAGS] [OPTIONS]
+
+FLAGS:
+ --flag_b first flag
+ --flag_a second flag
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --option_b <option_b> first option
+ --option_a <option_a> second option";
+
+static UNIFIED_HELP: &'static str = "test 1.2
+
+USAGE:
+ test [OPTIONS]
+
+OPTIONS:
+ --flag_a second flag
+ --flag_b first flag
+ -h, --help Prints help information
+ --option_a <option_a> second option
+ --option_b <option_b> first option
+ -V, --version Prints version information";
+
+static UNIFIED_HELP_AND_DERIVE: &'static str = "test 1.2
+
+USAGE:
+ test [OPTIONS]
+
+OPTIONS:
+ --flag_b first flag
+ --option_b <option_b> first option
+ --flag_a second flag
+ --option_a <option_a> second option
+ -h, --help Prints help information
+ -V, --version Prints version information";
+
+static DERIVE_ORDER_SC_PROP: &'static str = "test-sub 1.2
+
+USAGE:
+ test sub [FLAGS] [OPTIONS]
+
+FLAGS:
+ --flag_b first flag
+ --flag_a second flag
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --option_b <option_b> first option
+ --option_a <option_a> second option";
+
+static UNIFIED_SC_PROP: &'static str = "test-sub 1.2
+
+USAGE:
+ test sub [OPTIONS]
+
+OPTIONS:
+ --flag_a second flag
+ --flag_b first flag
+ -h, --help Prints help information
+ --option_a <option_a> second option
+ --option_b <option_b> first option
+ -V, --version Prints version information";
+
+static UNIFIED_DERIVE_SC_PROP: &'static str = "test-sub 1.2
+
+USAGE:
+ test sub [OPTIONS]
+
+OPTIONS:
+ --flag_b first flag
+ --option_b <option_b> first option
+ --flag_a second flag
+ --option_a <option_a> second option
+ -h, --help Prints help information
+ -V, --version Prints version information";
+
+static UNIFIED_DERIVE_SC_PROP_EXPLICIT_ORDER: &'static str = "test-sub 1.2
+
+USAGE:
+ test sub [OPTIONS]
+
+OPTIONS:
+ --flag_a second flag
+ --flag_b first flag
+ --option_b <option_b> first option
+ --option_a <option_a> second option
+ -h, --help Prints help information
+ -V, --version Prints version information";
+
+#[test]
+fn no_derive_order() {
+ let app = App::new("test")
+ .version("1.2")
+ .args(&[
+ Arg::with_name("flag_b").long("flag_b").help("first flag"),
+ Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"),
+ Arg::with_name("flag_a").long("flag_a").help("second flag"),
+ Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"),
+ ]);
+
+ assert!(test::compare_output(app, "test --help", NO_DERIVE_ORDER, false));
+}
+
+#[test]
+fn derive_order() {
+ let app = App::new("test")
+ .setting(AppSettings::DeriveDisplayOrder)
+ .version("1.2")
+ .args(&[
+ Arg::with_name("flag_b").long("flag_b").help("first flag"),
+ Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"),
+ Arg::with_name("flag_a").long("flag_a").help("second flag"),
+ Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"),
+ ]);
+
+ assert!(test::compare_output(app, "test --help", DERIVE_ORDER, false));
+}
+
+#[test]
+fn unified_help() {
+ let app = App::new("test")
+ .setting(AppSettings::UnifiedHelpMessage)
+ .version("1.2")
+ .args(&[
+ Arg::with_name("flag_b").long("flag_b").help("first flag"),
+ Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"),
+ Arg::with_name("flag_a").long("flag_a").help("second flag"),
+ Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"),
+ ]);
+
+ assert!(test::compare_output(app, "test --help", UNIFIED_HELP, false));
+}
+
+#[test]
+fn unified_help_and_derive_order() {
+ let app = App::new("test")
+ .setting(AppSettings::DeriveDisplayOrder)
+ .setting(AppSettings::UnifiedHelpMessage)
+ .version("1.2")
+ .args(&[
+ Arg::with_name("flag_b").long("flag_b").help("first flag"),
+ Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"),
+ Arg::with_name("flag_a").long("flag_a").help("second flag"),
+ Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"),
+ ]);
+
+ assert!(test::compare_output(app, "test --help", UNIFIED_HELP_AND_DERIVE, false));
+}
+
+#[test]
+fn derive_order_subcommand_propagate() {
+ let app = App::new("test")
+ .global_setting(AppSettings::DeriveDisplayOrder)
+ .version("1.2")
+ .subcommand(SubCommand::with_name("sub")
+ .version("1.2")
+ .args(&[
+ Arg::with_name("flag_b").long("flag_b").help("first flag"),
+ Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"),
+ Arg::with_name("flag_a").long("flag_a").help("second flag"),
+ Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"),
+ ]));
+
+ assert!(test::compare_output(app, "test sub --help", DERIVE_ORDER_SC_PROP, false));
+}
+
+#[test]
+fn unified_help_subcommand_propagate() {
+ let app = App::new("test")
+ .global_setting(AppSettings::UnifiedHelpMessage)
+ .subcommand(SubCommand::with_name("sub")
+ .version("1.2")
+ .args(&[
+ Arg::with_name("flag_b").long("flag_b").help("first flag"),
+ Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"),
+ Arg::with_name("flag_a").long("flag_a").help("second flag"),
+ Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"),
+ ]));
+
+ assert!(test::compare_output(app, "test sub --help", UNIFIED_SC_PROP, false));
+}
+
+#[test]
+fn unified_help_and_derive_order_subcommand_propagate() {
+ let app = App::new("test")
+ .global_setting(AppSettings::DeriveDisplayOrder)
+ .global_setting(AppSettings::UnifiedHelpMessage)
+ .subcommand(SubCommand::with_name("sub")
+ .version("1.2")
+ .args(&[
+ Arg::with_name("flag_b").long("flag_b").help("first flag"),
+ Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"),
+ Arg::with_name("flag_a").long("flag_a").help("second flag"),
+ Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"),
+ ]));
+
+ assert!(test::compare_output(app, "test sub --help", UNIFIED_DERIVE_SC_PROP, false));
+}
+
+#[test]
+fn unified_help_and_derive_order_subcommand_propagate_with_explicit_display_order() {
+ let app = App::new("test")
+ .global_setting(AppSettings::DeriveDisplayOrder)
+ .global_setting(AppSettings::UnifiedHelpMessage)
+ .subcommand(SubCommand::with_name("sub")
+ .version("1.2")
+ .args(&[
+ Arg::with_name("flag_b").long("flag_b").help("first flag"),
+ Arg::with_name("option_b").long("option_b").takes_value(true).help("first option"),
+ Arg::with_name("flag_a").long("flag_a").help("second flag").display_order(0),
+ Arg::with_name("option_a").long("option_a").takes_value(true).help("second option"),
+ ]));
+
+ assert!(test::compare_output(app, "test sub --help", UNIFIED_DERIVE_SC_PROP_EXPLICIT_ORDER, false));
+}
diff --git a/clap/tests/env.rs b/clap/tests/env.rs
new file mode 100644
index 0000000..62833ba
--- /dev/null
+++ b/clap/tests/env.rs
@@ -0,0 +1,263 @@
+extern crate clap;
+
+use std::env;
+use std::ffi::OsStr;
+
+use clap::{App, Arg};
+
+#[test]
+fn env() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(m.value_of("arg").unwrap(), "env");
+}
+
+#[test]
+fn env_os() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'").env_os(OsStr::new("CLP_TEST_ENV")),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(m.value_of("arg").unwrap(), "env");
+}
+
+#[test]
+fn no_env() {
+ // All the other tests use the presence of the Environment variable...
+ // we need another variable just in case one of the others is running at the same time...
+ env::remove_var("CLP_TEST_ENV_NONE");
+
+ let r = App::new("df")
+ .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV_NONE"))
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(!m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(m.value_of("arg"), None);
+}
+
+#[test]
+fn with_default() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'")
+ .env("CLP_TEST_ENV")
+ .default_value("default"),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(m.value_of("arg").unwrap(), "env");
+}
+
+#[test]
+fn opt_user_override() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("--arg [FILE] 'some arg'").env("CLP_TEST_ENV"),
+ )
+ .get_matches_from_safe(vec!["", "--arg", "opt"]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 1);
+ assert_eq!(m.value_of("arg").unwrap(), "opt");
+}
+
+#[test]
+fn positionals() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(m.value_of("arg").unwrap(), "env");
+}
+
+#[test]
+fn positionals_user_override() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
+ .get_matches_from_safe(vec!["", "opt"]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 1);
+ assert_eq!(m.value_of("arg").unwrap(), "opt");
+}
+
+#[test]
+fn multiple_one() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'")
+ .env("CLP_TEST_ENV")
+ .use_delimiter(true)
+ .multiple(true),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), vec!["env"]);
+}
+
+#[test]
+fn multiple_three() {
+ env::set_var("CLP_TEST_ENV_MULTI1", "env1,env2,env3");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'")
+ .env("CLP_TEST_ENV_MULTI1")
+ .use_delimiter(true)
+ .multiple(true),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(
+ m.values_of("arg").unwrap().collect::<Vec<_>>(),
+ vec!["env1", "env2", "env3"]
+ );
+}
+
+#[test]
+fn multiple_no_delimiter() {
+ env::set_var("CLP_TEST_ENV_MULTI2", "env1 env2 env3");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'")
+ .env("CLP_TEST_ENV_MULTI2")
+ .multiple(true),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(
+ m.values_of("arg").unwrap().collect::<Vec<_>>(),
+ vec!["env1 env2 env3"]
+ );
+}
+
+#[test]
+fn possible_value() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'")
+ .env("CLP_TEST_ENV")
+ .possible_value("env"),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(m.value_of("arg").unwrap(), "env");
+}
+
+
+#[test]
+fn not_possible_value() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'")
+ .env("CLP_TEST_ENV")
+ .possible_value("never"),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_err());
+}
+
+#[test]
+fn validator() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'")
+ .env("CLP_TEST_ENV")
+ .validator(|s| if s == "env" {
+ Ok(())
+ } else {
+ Err("not equal".to_string())
+ }),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("arg"), 0);
+ assert_eq!(m.value_of("arg").unwrap(), "env");
+}
+
+#[test]
+fn validator_invalid() {
+ env::set_var("CLP_TEST_ENV", "env");
+
+ let r = App::new("df")
+ .arg(
+ Arg::from_usage("[arg] 'some opt'")
+ .env("CLP_TEST_ENV")
+ .validator(|s| if s != "env" {
+ Ok(())
+ } else {
+ Err("is equal".to_string())
+ }),
+ )
+ .get_matches_from_safe(vec![""]);
+
+ assert!(r.is_err());
+}
diff --git a/clap/tests/example1_tmpl_full.txt b/clap/tests/example1_tmpl_full.txt
new file mode 100644
index 0000000..6ae57fa
--- /dev/null
+++ b/clap/tests/example1_tmpl_full.txt
@@ -0,0 +1,15 @@
+{bin} {version}
+{author}
+{about}
+
+USAGE:
+ {usage}
+
+FLAGS:
+{flags}
+OPTIONS:
+{options}
+ARGS:
+{positionals}
+SUBCOMMANDS:
+{subcommands}
diff --git a/clap/tests/example1_tmpl_simple.txt b/clap/tests/example1_tmpl_simple.txt
new file mode 100644
index 0000000..af6c4b0
--- /dev/null
+++ b/clap/tests/example1_tmpl_simple.txt
@@ -0,0 +1,8 @@
+{bin} {version}
+{author}
+{about}
+
+USAGE:
+ {usage}
+
+{all-args}
diff --git a/clap/tests/flags.rs b/clap/tests/flags.rs
new file mode 100644
index 0000000..143404e
--- /dev/null
+++ b/clap/tests/flags.rs
@@ -0,0 +1,147 @@
+extern crate clap;
+
+use clap::{App, Arg, ArgSettings};
+
+#[test]
+fn flag_using_short() {
+ let m = App::new("flag")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::from_usage("-c, --color 'some other flag'")
+ ])
+ .get_matches_from(vec!["", "-f", "-c"]);
+ assert!(m.is_present("flag"));
+ assert!(m.is_present("color"));
+}
+
+#[test]
+fn lots_o_flags_sep() {
+ let r = App::new("opts")
+ .arg(
+ Arg::from_usage("-o... 'some flag'"),
+ )
+ .get_matches_from_safe(vec!["",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
+ ]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
+}
+
+#[test]
+fn lots_o_flags_combined() {
+ let r = App::new("opts")
+ .arg(
+ Arg::from_usage("-o... 'some flag'"),
+ )
+ .get_matches_from_safe(vec!["",
+ "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
+ "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
+ "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
+ "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
+ "-ooooooooooooooooooooooooooooooooooooooooo",
+ ]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
+}
+
+#[test]
+fn flag_using_long() {
+ let m = App::new("flag")
+ .args(&[
+ Arg::from_usage("--flag 'some flag'"),
+ Arg::from_usage("--color 'some other flag'")
+ ])
+ .get_matches_from(vec!["", "--flag", "--color"]);
+ assert!(m.is_present("flag"));
+ assert!(m.is_present("color"));
+}
+
+#[test]
+fn flag_using_mixed() {
+ let m = App::new("flag")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::from_usage("-c, --color 'some other flag'")
+ ])
+ .get_matches_from(vec!["", "-f", "--color"]);
+ assert!(m.is_present("flag"));
+ assert!(m.is_present("color"));
+
+ let m = App::new("flag")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::from_usage("-c, --color 'some other flag'")
+ ])
+ .get_matches_from(vec!["", "--flag", "-c"]);
+ assert!(m.is_present("flag"));
+ assert!(m.is_present("color"));
+}
+
+#[test]
+fn multiple_flags_in_single() {
+ let m = App::new("multe_flags")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::from_usage("-c, --color 'some other flag'"),
+ Arg::from_usage("-d, --debug 'another other flag'")
+ ])
+ .get_matches_from(vec!["", "-fcd"]);
+ assert!(m.is_present("flag"));
+ assert!(m.is_present("color"));
+ assert!(m.is_present("debug"));
+}
+
+#[test]
+fn short_flag_misspel() {
+ let a = Arg::from_usage("-f1, --flag 'some flag'");
+ assert_eq!(a.b.name, "flag");
+ assert_eq!(a.s.short.unwrap(), 'f');
+ assert_eq!(a.s.long.unwrap(), "flag");
+ assert_eq!(a.b.help.unwrap(), "some flag");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.v.val_names.is_none());
+ assert!(a.v.num_vals.is_none());
+}
+
+#[test]
+fn short_flag_name_missing() {
+ let a = Arg::from_usage("-f 'some flag'");
+ assert_eq!(a.b.name, "f");
+ assert_eq!(a.s.short.unwrap(), 'f');
+ assert!(a.s.long.is_none());
+ assert_eq!(a.b.help.unwrap(), "some flag");
+ assert!(!a.is_set(ArgSettings::Multiple));
+ assert!(a.v.val_names.is_none());
+ assert!(a.v.num_vals.is_none());
+
+}
diff --git a/clap/tests/global_args.rs b/clap/tests/global_args.rs
new file mode 100644
index 0000000..4adc685
--- /dev/null
+++ b/clap/tests/global_args.rs
@@ -0,0 +1,37 @@
+extern crate clap;
+extern crate regex;
+
+#[cfg(test)]
+mod tests {
+ include!("../clap-test.rs");
+ use clap::{App, Arg, SubCommand};
+
+ fn get_app() -> App<'static, 'static> {
+ App::new("myprog")
+ .arg(Arg::with_name("GLOBAL_ARG")
+ .long("global-arg")
+ .help(
+ "Specifies something needed by the subcommands",
+ )
+ .global(true)
+ .takes_value(true)
+ .default_value("default_value"))
+ .arg(Arg::with_name("GLOBAL_FLAG")
+ .long("global-flag")
+ .help(
+ "Specifies something needed by the subcommands",
+ )
+ .multiple(true)
+ .global(true))
+ .subcommand(SubCommand::with_name("outer")
+ .subcommand(SubCommand::with_name("inner")))
+ }
+
+ #[test]
+ fn issue_1076() {
+ let mut app = get_app();
+ let _ = app.get_matches_from_safe_borrow(vec!["myprog"]);
+ let _ = app.get_matches_from_safe_borrow(vec!["myprog"]);
+ let _ = app.get_matches_from_safe_borrow(vec!["myprog"]);
+ }
+}
diff --git a/clap/tests/groups.rs b/clap/tests/groups.rs
new file mode 100644
index 0000000..bb108ea
--- /dev/null
+++ b/clap/tests/groups.rs
@@ -0,0 +1,207 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, Arg, ArgGroup, ErrorKind, SubCommand};
+
+static REQ_GROUP_USAGE: &'static str = "error: The following required arguments were not provided:
+ <base|--delete>
+
+USAGE:
+ clap-test <base|--delete>
+
+For more information try --help";
+
+static REQ_GROUP_CONFLICT_USAGE: &'static str = "error: The argument '<base>' cannot be used with '--delete'
+
+USAGE:
+ clap-test <base|--delete>
+
+For more information try --help";
+
+static REQ_GROUP_CONFLICT_REV: &'static str = "error: The argument '--delete' cannot be used with 'base'
+
+USAGE:
+ clap-test <base|--delete>
+
+For more information try --help";
+
+#[test]
+fn required_group_missing_arg() {
+ let result = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color 'some other flag'")
+ .group(ArgGroup::with_name("req")
+ .args(&["flag", "color"])
+ .required(true))
+ .get_matches_from_safe(vec![""]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+#[should_panic]
+fn non_existing_arg() {
+ let _ = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color 'some other flag'")
+ .group(ArgGroup::with_name("req")
+ .args(&["flg", "color"])
+ .required(true))
+ .get_matches_from_safe(vec![""]);
+}
+
+#[test]
+#[should_panic(expected = "The group 'c' contains the arg 'd' that doesn't actually exist.")]
+fn non_existing_arg_in_subcommand_help() {
+ let _ = App::new("a")
+ .subcommand(
+ SubCommand::with_name("b")
+ .group(
+ ArgGroup::with_name("c")
+ .args(&["d"])
+ .required(true),
+ )
+ ).get_matches_from_safe(vec!["a", "help", "b"]);
+}
+
+#[test]
+fn group_single_value() {
+ let res = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color [color] 'some option'")
+ .group(ArgGroup::with_name("grp")
+ .args(&["flag", "color"]))
+ .get_matches_from_safe(vec!["", "-c", "blue"]);
+ assert!(res.is_ok());
+
+ let m = res.unwrap();
+ assert!(m.is_present("grp"));
+ assert_eq!(m.value_of("grp").unwrap(), "blue");
+}
+
+#[test]
+fn group_single_flag() {
+ let res = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color [color] 'some option'")
+ .group(ArgGroup::with_name("grp")
+ .args(&["flag", "color"]))
+ .get_matches_from_safe(vec!["", "-f"]);
+ assert!(res.is_ok());
+
+ let m = res.unwrap();
+ assert!(m.is_present("grp"));
+ assert!(m.value_of("grp").is_none());
+}
+
+#[test]
+fn group_empty() {
+ let res = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color [color] 'some option'")
+ .group(ArgGroup::with_name("grp")
+ .args(&["flag", "color"]))
+ .get_matches_from_safe(vec![""]);
+ assert!(res.is_ok());
+
+ let m = res.unwrap();
+ assert!(!m.is_present("grp"));
+ assert!(m.value_of("grp").is_none());
+}
+
+#[test]
+fn group_reqired_flags_empty() {
+ let result = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color 'some option'")
+ .group(ArgGroup::with_name("grp")
+ .required(true)
+ .args(&["flag", "color"]))
+ .get_matches_from_safe(vec![""]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn group_multi_value_single_arg() {
+ let res = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color [color]... 'some option'")
+ .group(ArgGroup::with_name("grp")
+ .args(&["flag", "color"]))
+ .get_matches_from_safe(vec!["", "-c", "blue", "red", "green"]);
+ assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
+
+ let m = res.unwrap();
+ assert!(m.is_present("grp"));
+ assert_eq!(&*m.values_of("grp").unwrap().collect::<Vec<_>>(), &["blue", "red", "green"]);
+}
+
+#[test]
+fn empty_group() {
+ let r = App::new("empty_group")
+ .arg(Arg::from_usage("-f, --flag 'some flag'"))
+ .group(ArgGroup::with_name("vers")
+ .required(true))
+ .get_matches_from_safe(vec!["empty_prog"]);
+ assert!(r.is_err());
+ let err = r.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn req_group_usage_string() {
+ let app = App::new("req_group")
+ .args_from_usage("[base] 'Base commit'
+ -d, --delete 'Remove the base commit information'")
+ .group(ArgGroup::with_name("base_or_delete")
+ .args(&["base", "delete"])
+ .required(true));
+
+ assert!(test::compare_output(app, "clap-test", REQ_GROUP_USAGE, true));
+}
+
+#[test]
+fn req_group_with_conflict_usage_string() {
+ let app = App::new("req_group")
+ .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete"))
+ .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'"))
+ .group(ArgGroup::with_name("base_or_delete")
+ .args(&["base", "delete"])
+ .required(true));
+
+ assert!(test::compare_output2(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, REQ_GROUP_CONFLICT_USAGE, true));
+}
+
+#[test]
+fn required_group_multiple_args() {
+ let result = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color 'some other flag'")
+ .group(ArgGroup::with_name("req")
+ .args(&["flag", "color"])
+ .required(true)
+ .multiple(true))
+ .get_matches_from_safe(vec!["group", "-f", "-c"]);
+ assert!(result.is_ok());
+ let m = result.unwrap();
+ assert!(m.is_present("flag"));
+ assert!(m.is_present("color"));
+}
+
+#[test]
+fn group_multiple_args_error() {
+ let result = App::new("group")
+ .args_from_usage("-f, --flag 'some flag'
+ -c, --color 'some other flag'")
+ .group(ArgGroup::with_name("req")
+ .args(&["flag", "color"]))
+ .get_matches_from_safe(vec!["group", "-f", "-c"]);
+ assert!(result.is_err());
+ let err = result.unwrap_err();
+ assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+}
diff --git a/clap/tests/help.rs b/clap/tests/help.rs
new file mode 100644
index 0000000..4b15281
--- /dev/null
+++ b/clap/tests/help.rs
@@ -0,0 +1,1205 @@
+#[macro_use]
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, AppSettings, SubCommand, ErrorKind, Arg};
+
+static REQUIRE_DELIM_HELP: &'static str = "test 1.3
+Kevin K.
+tests stuff
+
+USAGE:
+ test --fake <some>:<val>
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -f, --fake <some>:<val> some help";
+
+static HELP: &'static str = "clap-test v1.4.8
+Kevin K. <kbknapp@gmail.com>
+tests clap library
+
+USAGE:
+ clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]
+
+FLAGS:
+ -f, --flag tests flags
+ -F tests flags with exclusions
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -O, --Option <option3> specific vals [possible values: fast, slow]
+ --long-option-2 <option2> tests long options with exclusions
+ --maxvals3 <maxvals>... Tests 3 max vals
+ --minvals2 <minvals>... Tests 2 min vals
+ --multvals <one> <two> Tests multiple values, not mult occs
+ --multvalsmo <one> <two> Tests multiple values, and mult occs
+ -o, --option <opt>... tests options
+
+ARGS:
+ <positional> tests positionals
+ <positional2> tests positionals with exclusions
+ <positional3>... tests specific values [possible values: vi, emacs]
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ subcmd tests subcommands";
+
+static SC_NEGATES_REQS: &'static str = "prog 1.0
+
+USAGE:
+ prog --opt <FILE> [PATH]
+ prog [PATH] <SUBCOMMAND>
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --opt <FILE> tests options
+
+ARGS:
+ <PATH> help
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test";
+
+static ARGS_NEGATE_SC: &'static str = "prog 1.0
+
+USAGE:
+ prog [FLAGS] [OPTIONS] [PATH]
+ prog <SUBCOMMAND>
+
+FLAGS:
+ -f, --flag testing flags
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --opt <FILE> tests options
+
+ARGS:
+ <PATH> help
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test";
+
+static AFTER_HELP: &'static str = "some text that comes before the help
+
+clap-test v1.4.8
+tests clap library
+
+USAGE:
+ clap-test
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+some text that comes after the help";
+
+static HIDDEN_ARGS: &'static str = "prog 1.0
+
+USAGE:
+ prog [FLAGS] [OPTIONS]
+
+FLAGS:
+ -f, --flag testing flags
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --opt <FILE> tests options";
+
+static SC_HELP: &'static str = "clap-test-subcmd 0.1
+Kevin K. <kbknapp@gmail.com>
+tests subcommands
+
+USAGE:
+ clap-test subcmd [FLAGS] [OPTIONS] [--] [scpositional]
+
+FLAGS:
+ -f, --flag tests flags
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --option <scoption>... tests options
+ -s, --subcmdarg <subcmdarg> tests other args
+
+ARGS:
+ <scpositional> tests positionals";
+
+static ISSUE_1046_HIDDEN_SCS: &'static str = "prog 1.0
+
+USAGE:
+ prog [FLAGS] [OPTIONS] [PATH]
+
+FLAGS:
+ -f, --flag testing flags
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --opt <FILE> tests options
+
+ARGS:
+ <PATH> some";
+
+// Using number_of_values(1) with multiple(true) misaligns help message
+static ISSUE_760: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -O, --opt <opt> tests options
+ -o, --option <option>... tests options";
+
+static RIPGREP_USAGE: &'static str = "ripgrep 0.5
+
+USAGE:
+ rg [OPTIONS] <pattern> [<path> ...]
+ rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
+ rg [OPTIONS] --files [<path> ...]
+ rg [OPTIONS] --type-list
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information";
+
+
+static MULTI_SC_HELP: &'static str = "ctest-subcmd-multi 0.1
+Kevin K. <kbknapp@gmail.com>
+tests subcommands
+
+USAGE:
+ ctest subcmd multi [FLAGS] [OPTIONS]
+
+FLAGS:
+ -f, --flag tests flags
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -o, --option <scoption>... tests options";
+
+static ISSUE_626_CUTOFF: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --cafe <FILE> A coffeehouse, coffee shop, or café is an
+ establishment which primarily serves hot
+ coffee, related coffee beverages (e.g., café
+ latte, cappuccino, espresso), tea, and other
+ hot beverages. Some coffeehouses also serve
+ cold beverages such as iced coffee and iced
+ tea. Many cafés also serve some type of food,
+ such as light snacks, muffins, or pastries.";
+
+static ISSUE_626_PANIC: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --cafe <FILE>
+ La culture du café est très développée
+ dans de nombreux pays à climat chaud
+ d\'Amérique, d\'Afrique et d\'Asie, dans
+ des plantations qui sont cultivées pour
+ les marchés d\'exportation. Le café est
+ souvent une contribution majeure aux
+ exportations des régions productrices.";
+
+static HIDE_POS_VALS: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --cafe <FILE> A coffeehouse, coffee shop, or café.
+ -p, --pos <VAL> Some vals [possible values: fast, slow]";
+
+static FINAL_WORD_WRAPPING: &'static str = "ctest 0.1
+
+USAGE:
+ ctest
+
+FLAGS:
+ -h, --help
+ Prints help
+ information
+ -V, --version
+ Prints
+ version
+ information";
+
+static OLD_NEWLINE_CHARS: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [FLAGS]
+
+FLAGS:
+ -h, --help Prints help information
+ -m Some help with some wrapping
+ (Defaults to something)
+ -V, --version Prints version information";
+
+static WRAPPING_NEWLINE_CHARS: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [mode]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ <mode> x, max, maximum 20 characters, contains
+ symbols.
+ l, long Copy-friendly, 14
+ characters, contains symbols.
+ m, med, medium Copy-friendly, 8
+ characters, contains symbols.";
+
+static ISSUE_688: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --filter <filter> Sets the filter, or sampling method, to use for interpolation when resizing the particle
+ images. The default is Linear (Bilinear). [possible values: Nearest, Linear, Cubic,
+ Gaussian, Lanczos3]";
+
+static ISSUE_702: &'static str = "myapp 1.0
+foo
+bar
+
+USAGE:
+ myapp [OPTIONS] [--] [ARGS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -l, --label <label>... a label
+ -o, --other <other> some other option
+ -s, --some <some> some option
+
+ARGS:
+ <arg1> some option
+ <arg2>... some option";
+
+static ISSUE_777: &'static str = "A app with a crazy very long long
+long name hahaha 1.0
+Some Very Long Name and crazy long
+email <email@server.com>
+Show how the about text is not
+wrapped
+
+USAGE:
+ ctest
+
+FLAGS:
+ -h, --help
+ Prints help information
+
+ -V, --version
+ Prints version
+ information";
+
+static CUSTOM_VERSION_AND_HELP: &'static str = "customize 0.1
+Nobody <odysseus@example.com>
+You can customize the version and help text
+
+USAGE:
+ customize
+
+FLAGS:
+ -H, --help Print help information
+ -v, --version Print version information";
+
+static LAST_ARG: &'static str = "last 0.1
+
+USAGE:
+ last <TARGET> [CORPUS] [-- <ARGS>...]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ <TARGET> some
+ <CORPUS> some
+ <ARGS>... some";
+
+static LAST_ARG_SC: &'static str = "last 0.1
+
+USAGE:
+ last <TARGET> [CORPUS] [-- <ARGS>...]
+ last <SUBCOMMAND>
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ <TARGET> some
+ <CORPUS> some
+ <ARGS>... some
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test some";
+
+static LAST_ARG_REQ: &'static str = "last 0.1
+
+USAGE:
+ last <TARGET> [CORPUS] -- <ARGS>...
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ <TARGET> some
+ <CORPUS> some
+ <ARGS>... some";
+
+static LAST_ARG_REQ_SC: &'static str = "last 0.1
+
+USAGE:
+ last <TARGET> [CORPUS] -- <ARGS>...
+ last <SUBCOMMAND>
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ <TARGET> some
+ <CORPUS> some
+ <ARGS>... some
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test some";
+
+static HIDE_DEFAULT_VAL: &'static str = "default 0.1
+
+USAGE:
+ default [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --arg <argument> Pass an argument to the program. [default: default-argument]";
+
+static LAST_ARG_USAGE: &'static str = "flamegraph 0.1
+
+USAGE:
+ flamegraph [FLAGS] [OPTIONS] [BINFILE] [-- <ARGS>...]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+ -v, --verbose Prints out more stuff.
+
+OPTIONS:
+ -f, --frequency <HERTZ> The sampling frequency.
+ -t, --timeout <SECONDS> Timeout in seconds.
+
+ARGS:
+ <BINFILE> The path of the binary to be profiled. for a binary.
+ <ARGS>... Any arguments you wish to pass to the being profiled.";
+
+static LAST_ARG_REQ_MULT: &'static str = "example 1.0
+
+USAGE:
+ example <FIRST>... [--] <SECOND>...
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ <FIRST>... First
+ <SECOND>... Second";
+
+static DEFAULT_HELP: &'static str = "ctest 1.0
+
+USAGE:
+ ctest
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information";
+
+static LONG_ABOUT: &'static str = "myapp 1.0
+foo
+something really really long, with
+multiple lines of text
+that should be displayed
+
+USAGE:
+ myapp [arg1]
+
+FLAGS:
+ -h, --help
+ Prints help information
+
+ -V, --version
+ Prints version information
+
+
+ARGS:
+ <arg1>
+ some option";
+
+static HIDE_ENV_VALS: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --cafe <FILE> A coffeehouse, coffee shop, or café. [env: ENVVAR]
+ -p, --pos <VAL> Some vals [possible values: fast, slow]";
+
+static SHOW_ENV_VALS: &'static str = "ctest 0.1
+
+USAGE:
+ ctest [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --cafe <FILE> A coffeehouse, coffee shop, or café. [env: ENVVAR=MYVAL]
+ -p, --pos <VAL> Some vals [possible values: fast, slow]";
+
+fn setup() -> App<'static, 'static> {
+ App::new("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.3")
+}
+
+#[test]
+fn help_short() {
+ let m = setup()
+ .get_matches_from_safe(vec!["myprog", "-h"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
+}
+
+#[test]
+fn help_long() {
+ let m = setup()
+ .get_matches_from_safe(vec!["myprog", "--help"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
+}
+
+#[test]
+fn help_no_subcommand() {
+ let m = setup()
+ .get_matches_from_safe(vec!["myprog", "help"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn help_subcommand() {
+ let m = setup()
+ .subcommand(SubCommand::with_name("test")
+ .about("tests things")
+ .arg_from_usage("-v --verbose 'with verbosity'"))
+ .get_matches_from_safe(vec!["myprog", "help"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
+}
+
+#[test]
+fn req_last_arg_usage() {
+ let app = clap_app!(example =>
+ (version: "1.0")
+ (@arg FIRST: ... * "First")
+ (@arg SECOND: ... * +last "Second")
+ );
+ assert!(test::compare_output(app, "example --help", LAST_ARG_REQ_MULT, false));
+}
+
+#[test]
+fn args_with_last_usage() {
+ let app = App::new("flamegraph")
+ .version("0.1")
+ .setting(AppSettings::TrailingVarArg)
+ .arg(Arg::with_name("verbose")
+ .help("Prints out more stuff.")
+ .short("v")
+ .long("verbose")
+ .multiple(true)
+ )
+ .arg(Arg::with_name("timeout")
+ .help("Timeout in seconds.")
+ .short("t")
+ .long("timeout")
+ .value_name("SECONDS")
+ .takes_value(true)
+ )
+ .arg(Arg::with_name("frequency")
+ .help("The sampling frequency.")
+ .short("f")
+ .long("frequency")
+ .value_name("HERTZ")
+ .takes_value(true)
+ )
+ .arg(Arg::with_name("binary path")
+ .help("The path of the binary to be profiled. for a binary.")
+ .takes_value(true)
+ .value_name("BINFILE")
+ )
+ .arg(Arg::with_name("pass through args")
+ .help("Any arguments you wish to pass to the being profiled.")
+ .value_name("ARGS")
+ .last(true)
+ .multiple(true)
+ );
+ assert!(test::compare_output(app, "flamegraph --help", LAST_ARG_USAGE, false));
+}
+
+#[test]
+fn subcommand_short_help() {
+ let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
+}
+
+#[test]
+fn subcommand_long_help() {
+ let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
+}
+
+#[test]
+fn subcommand_help_rev() {
+ let m = test::complex_app().get_matches_from_safe(vec!["clap-test", "help", "subcmd"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
+}
+
+#[test]
+fn complex_help_output() {
+ assert!(test::compare_output(test::complex_app(), "clap-test --help", HELP, false));
+}
+
+#[test]
+fn after_and_before_help_output() {
+ let app = App::new("clap-test")
+ .version("v1.4.8")
+ .about("tests clap library")
+ .before_help("some text that comes before the help")
+ .after_help("some text that comes after the help");
+ assert!(test::compare_output(app, "clap-test --help", AFTER_HELP, false));
+}
+
+#[test]
+fn multi_level_sc_help() {
+ let app = App::new("ctest")
+ .subcommand(SubCommand::with_name("subcmd").subcommand(SubCommand::with_name("multi")
+ .about("tests subcommands")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .version("0.1")
+ .args_from_usage("
+ -f, --flag 'tests flags'
+ -o, --option [scoption]... 'tests options'
+ ")));
+ assert!(test::compare_output(app, "ctest help subcmd multi", MULTI_SC_HELP, false));
+}
+
+#[test]
+fn no_wrap_help() {
+ let app = App::new("ctest")
+ .set_term_width(0)
+ .help(MULTI_SC_HELP);
+ assert!(test::compare_output(app, "ctest --help", MULTI_SC_HELP, false));
+}
+
+#[test]
+fn no_wrap_default_help() {
+ let app = App::new("ctest").version("1.0").set_term_width(0);
+ assert!(test::compare_output(app, "ctest --help", DEFAULT_HELP, false));
+}
+
+#[test]
+fn complex_subcommand_help_output() {
+ let a = test::complex_app();
+ assert!(test::compare_output(a, "clap-test subcmd --help", SC_HELP, false));
+}
+
+
+#[test]
+fn issue_626_unicode_cutoff() {
+ let app = App::new("ctest")
+ .version("0.1")
+ .set_term_width(70)
+ .arg(Arg::with_name("cafe")
+ .short("c")
+ .long("cafe")
+ .value_name("FILE")
+ .help("A coffeehouse, coffee shop, or café is an establishment \
+ which primarily serves hot coffee, related coffee beverages \
+ (e.g., café latte, cappuccino, espresso), tea, and other hot \
+ beverages. Some coffeehouses also serve cold beverages such as \
+ iced coffee and iced tea. Many cafés also serve some type of \
+ food, such as light snacks, muffins, or pastries.")
+ .takes_value(true));
+ assert!(test::compare_output(app, "ctest --help", ISSUE_626_CUTOFF, false));
+}
+
+#[test]
+fn hide_possible_vals() {
+ let app = App::new("ctest")
+ .version("0.1")
+ .arg(Arg::with_name("pos")
+ .short("p")
+ .long("pos")
+ .value_name("VAL")
+ .possible_values(&["fast", "slow"])
+ .help("Some vals")
+ .takes_value(true))
+ .arg(Arg::with_name("cafe")
+ .short("c")
+ .long("cafe")
+ .value_name("FILE")
+ .hide_possible_values(true)
+ .possible_values(&["fast", "slow"])
+ .help("A coffeehouse, coffee shop, or café.")
+ .takes_value(true));
+ assert!(test::compare_output(app, "ctest --help", HIDE_POS_VALS, false));
+}
+
+#[test]
+fn issue_626_panic() {
+ let app = App::new("ctest")
+ .version("0.1")
+ .set_term_width(52)
+ .arg(Arg::with_name("cafe")
+ .short("c")
+ .long("cafe")
+ .value_name("FILE")
+ .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \
+ d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \
+ Le café est souvent une contribution majeure aux exportations des régions productrices.")
+ .takes_value(true));
+ assert!(test::compare_output(app, "ctest --help", ISSUE_626_PANIC, false));
+}
+
+#[test]
+fn issue_626_variable_panic() {
+ for i in 10..320 {
+ let _ = App::new("ctest")
+ .version("0.1")
+ .set_term_width(i)
+ .arg(Arg::with_name("cafe")
+ .short("c")
+ .long("cafe")
+ .value_name("FILE")
+ .help("La culture du café est très développée dans de nombreux pays à climat chaud d'Amérique, \
+ d'Afrique et d'Asie, dans des plantations qui sont cultivées pour les marchés d'exportation. \
+ Le café est souvent une contribution majeure aux exportations des régions productrices.")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["ctest", "--help"]);
+ }
+}
+
+#[test]
+fn final_word_wrapping() {
+ let app = App::new("ctest").version("0.1").set_term_width(24);
+ assert!(test::compare_output(app, "ctest --help", FINAL_WORD_WRAPPING, false));
+}
+
+#[test]
+fn wrapping_newline_chars() {
+ let app = App::new("ctest")
+ .version("0.1")
+ .set_term_width(60)
+ .arg(Arg::with_name("mode")
+ .help("x, max, maximum 20 characters, contains symbols.{n}\
+ l, long Copy-friendly, 14 characters, contains symbols.{n}\
+ m, med, medium Copy-friendly, 8 characters, contains symbols.{n}"));
+ assert!(test::compare_output(app, "ctest --help", WRAPPING_NEWLINE_CHARS, false));
+}
+
+#[test]
+fn old_newline_chars() {
+ let app = App::new("ctest")
+ .version("0.1")
+ .arg(Arg::with_name("mode")
+ .short("m")
+ .help("Some help with some wrapping{n}(Defaults to something)"));
+ assert!(test::compare_output(app, "ctest --help", OLD_NEWLINE_CHARS, false));
+}
+
+#[test]
+fn issue_688_hidden_pos_vals() {
+ let filter_values = ["Nearest", "Linear", "Cubic", "Gaussian", "Lanczos3"];
+
+ let app1 = App::new("ctest")
+ .version("0.1")
+ .set_term_width(120)
+ .setting(AppSettings::HidePossibleValuesInHelp)
+ .arg(Arg::with_name("filter")
+ .help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \
+ images. The default is Linear (Bilinear). [possible values: Nearest, Linear, Cubic, Gaussian, Lanczos3]")
+ .long("filter")
+ .possible_values(&filter_values)
+ .takes_value(true));
+ assert!(test::compare_output(app1, "ctest --help", ISSUE_688, false));
+
+ let app2 = App::new("ctest")
+ .version("0.1")
+ .set_term_width(120)
+ .arg(Arg::with_name("filter")
+ .help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \
+ images. The default is Linear (Bilinear).")
+ .long("filter")
+ .possible_values(&filter_values)
+ .takes_value(true));
+ assert!(test::compare_output(app2, "ctest --help", ISSUE_688, false));
+
+ let app3 = App::new("ctest")
+ .version("0.1")
+ .set_term_width(120)
+ .arg(Arg::with_name("filter")
+ .help("Sets the filter, or sampling method, to use for interpolation when resizing the particle \
+ images. The default is Linear (Bilinear). [possible values: Nearest, Linear, Cubic, Gaussian, Lanczos3]")
+ .long("filter")
+ .takes_value(true));
+ assert!(test::compare_output(app3, "ctest --help", ISSUE_688, false));
+}
+
+#[test]
+fn issue_702_multiple_values() {
+ let app = App::new("myapp")
+ .version("1.0")
+ .author("foo")
+ .about("bar")
+ .arg(Arg::with_name("arg1").help("some option"))
+ .arg(Arg::with_name("arg2")
+ .multiple(true)
+ .help("some option"))
+ .arg(Arg::with_name("some")
+ .help("some option")
+ .short("s")
+ .long("some")
+ .takes_value(true))
+ .arg(Arg::with_name("other")
+ .help("some other option")
+ .short("o")
+ .long("other")
+ .takes_value(true))
+ .arg(Arg::with_name("label")
+ .help("a label")
+ .short("l")
+ .long("label")
+ .multiple(true)
+ .takes_value(true));
+ assert!(test::compare_output(app, "myapp --help", ISSUE_702, false));
+}
+
+#[test]
+fn long_about() {
+ let app = App::new("myapp")
+ .version("1.0")
+ .author("foo")
+ .about("bar")
+ .long_about("something really really long, with\nmultiple lines of text\nthat should be displayed")
+ .arg(Arg::with_name("arg1").help("some option"));
+ assert!(test::compare_output(app, "myapp --help", LONG_ABOUT, false));
+}
+
+#[test]
+fn issue_760() {
+ let app = App::new("ctest")
+ .version("0.1")
+ .arg(Arg::with_name("option")
+ .help("tests options")
+ .short("o")
+ .long("option")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1))
+ .arg(Arg::with_name("opt")
+ .help("tests options")
+ .short("O")
+ .long("opt")
+ .takes_value(true));
+ assert!(test::compare_output(app, "ctest --help", ISSUE_760, false));
+}
+
+#[test]
+fn ripgrep_usage() {
+ let app = App::new("ripgrep")
+ .version("0.5")
+ .usage("rg [OPTIONS] <pattern> [<path> ...]
+ rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
+ rg [OPTIONS] --files [<path> ...]
+ rg [OPTIONS] --type-list");
+
+ assert!(test::compare_output(app, "rg --help", RIPGREP_USAGE, false));
+}
+
+#[test]
+fn ripgrep_usage_using_templates() {
+ let app = App::new("ripgrep")
+ .version("0.5")
+ .usage("
+ rg [OPTIONS] <pattern> [<path> ...]
+ rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
+ rg [OPTIONS] --files [<path> ...]
+ rg [OPTIONS] --type-list")
+ .template("\
+{bin} {version}
+
+USAGE:{usage}
+
+FLAGS:
+{flags}");
+
+ assert!(test::compare_output(app, "rg --help", RIPGREP_USAGE, false));
+}
+
+#[test]
+fn sc_negates_reqs() {
+ let app = App::new("prog")
+ .version("1.0")
+ .setting(AppSettings::SubcommandsNegateReqs)
+ .arg_from_usage("-o, --opt <FILE> 'tests options'")
+ .arg(Arg::with_name("PATH").help("help"))
+ .subcommand(SubCommand::with_name("test"));
+ assert!(test::compare_output(app, "prog --help", SC_NEGATES_REQS, false));
+}
+
+#[test]
+fn hidden_args() {
+ let app = App::new("prog")
+ .version("1.0")
+ .args_from_usage("-f, --flag 'testing flags'
+ -o, --opt [FILE] 'tests options'")
+ .arg(Arg::with_name("pos").hidden(true));
+ assert!(test::compare_output(app, "prog --help", HIDDEN_ARGS, false));
+}
+
+#[test]
+fn args_negate_sc() {
+ let app = App::new("prog")
+ .version("1.0")
+ .setting(AppSettings::ArgsNegateSubcommands)
+ .args_from_usage("-f, --flag 'testing flags'
+ -o, --opt [FILE] 'tests options'")
+ .arg(Arg::with_name("PATH").help("help"))
+ .subcommand(SubCommand::with_name("test"));
+ assert!(test::compare_output(app, "prog --help", ARGS_NEGATE_SC, false));
+}
+
+#[test]
+fn issue_1046_hidden_scs() {
+ let app = App::new("prog")
+ .version("1.0")
+ .args_from_usage("-f, --flag 'testing flags'
+ -o, --opt [FILE] 'tests options'")
+ .arg(Arg::with_name("PATH").help("some"))
+ .subcommand(SubCommand::with_name("test").setting(AppSettings::Hidden));
+ assert!(test::compare_output(app, "prog --help", ISSUE_1046_HIDDEN_SCS, false));
+}
+
+#[test]
+fn issue_777_wrap_all_things() {
+ let app = App::new("A app with a crazy very long long long name hahaha")
+ .version("1.0")
+ .author("Some Very Long Name and crazy long email <email@server.com>")
+ .about("Show how the about text is not wrapped")
+ .set_term_width(35);
+ assert!(test::compare_output(app, "ctest --help", ISSUE_777, false));
+}
+
+#[test]
+fn customize_version_and_help() {
+ let app = App::new("customize")
+ .version("0.1")
+ .author("Nobody <odysseus@example.com>")
+ .about("You can customize the version and help text")
+ .help_short("H")
+ .help_message("Print help information")
+ .version_short("v")
+ .version_message("Print version information");
+ assert!(test::compare_output(app, "customize --help", CUSTOM_VERSION_AND_HELP, false));
+}
+
+#[test]
+fn last_arg_mult_usage() {
+ let app = App::new("last")
+ .version("0.1")
+ .arg(Arg::with_name("TARGET").required(true).help("some"))
+ .arg(Arg::with_name("CORPUS").help("some"))
+ .arg(Arg::with_name("ARGS").multiple(true).last(true).help("some"));
+ assert!(test::compare_output(app, "last --help", LAST_ARG, false));
+}
+
+#[test]
+fn last_arg_mult_usage_req() {
+ let app = App::new("last")
+ .version("0.1")
+ .arg(Arg::with_name("TARGET").required(true).help("some"))
+ .arg(Arg::with_name("CORPUS").help("some"))
+ .arg(Arg::with_name("ARGS").multiple(true).last(true).required(true).help("some"));
+ assert!(test::compare_output(app, "last --help", LAST_ARG_REQ, false));
+}
+
+#[test]
+fn last_arg_mult_usage_req_with_sc() {
+ let app = App::new("last")
+ .version("0.1")
+ .setting(AppSettings::SubcommandsNegateReqs)
+ .arg(Arg::with_name("TARGET").required(true).help("some"))
+ .arg(Arg::with_name("CORPUS").help("some"))
+ .arg(Arg::with_name("ARGS").multiple(true).last(true).required(true).help("some"))
+ .subcommand(SubCommand::with_name("test").about("some"));
+ assert!(test::compare_output(app, "last --help", LAST_ARG_REQ_SC, false));
+}
+
+#[test]
+fn last_arg_mult_usage_with_sc() {
+ let app = App::new("last")
+ .version("0.1")
+ .setting(AppSettings::ArgsNegateSubcommands)
+ .arg(Arg::with_name("TARGET").required(true).help("some"))
+ .arg(Arg::with_name("CORPUS").help("some"))
+ .arg(Arg::with_name("ARGS").multiple(true).last(true).help("some"))
+ .subcommand(SubCommand::with_name("test").about("some"));
+ assert!(test::compare_output(app, "last --help", LAST_ARG_SC, false));
+}
+
+
+#[test]
+fn hidden_default_val() {
+ let app1 = App::new("default")
+ .version("0.1")
+ .set_term_width(120)
+ .arg(Arg::with_name("argument")
+ .help("Pass an argument to the program. [default: default-argument]")
+ .long("arg")
+ .default_value("default-argument")
+ .hide_default_value(true));
+ assert!(test::compare_output(app1, "default --help", HIDE_DEFAULT_VAL, false));
+
+ let app2 = App::new("default")
+ .version("0.1")
+ .set_term_width(120)
+ .arg(Arg::with_name("argument")
+ .help("Pass an argument to the program.")
+ .long("arg")
+ .default_value("default-argument"));
+ assert!(test::compare_output(app2, "default --help", HIDE_DEFAULT_VAL, false));
+}
+
+fn issue_1112_setup() -> App<'static, 'static> {
+ App::new("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.3")
+ .arg(Arg::from_usage("-h, --help 'some help'"))
+ .subcommand(SubCommand::with_name("foo")
+ .arg(Arg::from_usage("-h, --help 'some help'")))
+}
+
+#[test]
+fn issue_1112_override_help_long() {
+ let m = issue_1112_setup()
+ .get_matches_from_safe(vec!["test", "--help"]);
+
+ assert!(m.is_ok());
+ assert!(m.unwrap().is_present("help"));
+}
+
+#[test]
+fn issue_1112_override_help_short() {
+ let m = issue_1112_setup()
+ .get_matches_from_safe(vec!["test", "-h"]);
+
+ assert!(m.is_ok());
+ assert!(m.unwrap().is_present("help"));
+}
+
+#[test]
+fn issue_1112_override_help_subcmd_long() {
+ let m = issue_1112_setup()
+ .get_matches_from_safe(vec!["test", "foo", "--help"]);
+
+ assert!(m.is_ok());
+ assert!(m.unwrap().subcommand_matches("foo").unwrap().is_present("help"));
+}
+
+#[test]
+fn issue_1112_override_help_subcmd_short() {
+ let m = issue_1112_setup()
+ .get_matches_from_safe(vec!["test", "foo", "-h"]);
+
+ assert!(m.is_ok());
+ assert!(m.unwrap().subcommand_matches("foo").unwrap().is_present("help"));
+}
+
+#[test]
+fn issue_1052_require_delim_help() {
+ let app = App::new("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.3")
+ .arg(Arg::from_usage("-f, --fake <some> <val> 'some help'").require_delimiter(true).value_delimiter(":"));
+
+ assert!(test::compare_output(app, "test --help", REQUIRE_DELIM_HELP, false));
+}
+
+#[test]
+fn hide_env_vals() {
+ use std::env;
+
+ env::set_var("ENVVAR", "MYVAL");
+ let app = App::new("ctest")
+ .version("0.1")
+ .arg(Arg::with_name("pos")
+ .short("p")
+ .long("pos")
+ .value_name("VAL")
+ .possible_values(&["fast", "slow"])
+ .help("Some vals")
+ .takes_value(true))
+ .arg(Arg::with_name("cafe")
+ .short("c")
+ .long("cafe")
+ .value_name("FILE")
+ .hide_env_values(true)
+ .env("ENVVAR")
+ .help("A coffeehouse, coffee shop, or café.")
+ .takes_value(true));
+ assert!(test::compare_output(app, "ctest --help", HIDE_ENV_VALS, false));
+}
+
+#[test]
+fn show_env_vals() {
+ use std::env;
+
+ env::set_var("ENVVAR", "MYVAL");
+ let app = App::new("ctest")
+ .version("0.1")
+ .arg(Arg::with_name("pos")
+ .short("p")
+ .long("pos")
+ .value_name("VAL")
+ .possible_values(&["fast", "slow"])
+ .help("Some vals")
+ .takes_value(true))
+ .arg(Arg::with_name("cafe")
+ .short("c")
+ .long("cafe")
+ .value_name("FILE")
+ .hide_possible_values(true)
+ .env("ENVVAR")
+ .help("A coffeehouse, coffee shop, or café.")
+ .takes_value(true));
+ assert!(test::compare_output(app, "ctest --help", SHOW_ENV_VALS, false));
+}
+
+static ISSUE_897: &'static str = "ctest-foo 0.1
+Long about foo
+
+USAGE:
+ ctest foo
+
+FLAGS:
+ -h, --help
+ Prints help information
+
+ -V, --version
+ Prints version information";
+
+#[test]
+fn show_long_about_issue_897() {
+ let app = App::new("ctest")
+ .version("0.1")
+ .subcommand(SubCommand::with_name("foo")
+ .version("0.1")
+ .about("About foo")
+ .long_about("Long about foo"));
+ assert!(test::compare_output(app, "ctest foo --help", ISSUE_897, false));
+}
+
+static ISSUE_897_SHORT: &'static str = "ctest-foo 0.1
+Long about foo
+
+USAGE:
+ ctest foo
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information";
+
+#[test]
+fn show_short_about_issue_897() {
+ let app = App::new("ctest")
+ .version("0.1")
+ .subcommand(SubCommand::with_name("foo")
+ .version("0.1")
+ .about("About foo")
+ .long_about("Long about foo"));
+ assert!(test::compare_output(app, "ctest foo -h", ISSUE_897_SHORT, false));
+}
diff --git a/clap/tests/hidden_args.rs b/clap/tests/hidden_args.rs
new file mode 100644
index 0000000..635e25e
--- /dev/null
+++ b/clap/tests/hidden_args.rs
@@ -0,0 +1,178 @@
+extern crate clap;
+extern crate regex;
+
+use clap::{App, Arg};
+
+include!("../clap-test.rs");
+
+static HIDDEN_ARGS: &'static str = "test 1.4
+Kevin K.
+tests stuff
+
+USAGE:
+ test [FLAGS] [OPTIONS]
+
+FLAGS:
+ -F, --flag2 some other flag
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --option <opt> some option";
+
+#[test]
+fn hidden_args() {
+ let app = App::new("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.4")
+ .args(&[Arg::from_usage("-f, --flag 'some flag'").hidden(true),
+ Arg::from_usage("-F, --flag2 'some other flag'"),
+ Arg::from_usage("--option [opt] 'some option'"),
+ Arg::with_name("DUMMY").required(false).hidden(true)]);
+ assert!(test::compare_output(app, "test --help", HIDDEN_ARGS, false));
+}
+
+static HIDDEN_SHORT_ARGS: &'static str = "test 2.31.2
+Steve P.
+hides short args
+
+USAGE:
+ test [FLAGS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+ -v, --visible This text should be visible";
+
+static HIDDEN_SHORT_ARGS_LONG_HELP: &'static str = "test 2.31.2
+Steve P.
+hides short args
+
+USAGE:
+ test [FLAGS]
+
+FLAGS:
+ -c, --config
+ Some help text describing the --config arg
+
+ -h, --help
+ Prints help information
+
+ -V, --version
+ Prints version information
+
+ -v, --visible
+ This text should be visible";
+
+/// Ensure hidden with short option
+#[test]
+fn hidden_short_args() {
+ let app = App::new("test")
+ .about("hides short args")
+ .author("Steve P.")
+ .version("2.31.2")
+ .args(&[
+ Arg::with_name("cfg")
+ .short("c")
+ .long("config")
+ .hidden_short_help(true)
+ .help("Some help text describing the --config arg"),
+ Arg::with_name("visible")
+ .short("v")
+ .long("visible")
+ .help("This text should be visible")]);
+
+ assert!(test::compare_output(app, "test -h", HIDDEN_SHORT_ARGS, false));
+}
+
+/// Ensure visible with opposite option
+#[test]
+fn hidden_short_args_long_help() {
+ let app = App::new("test")
+ .about("hides short args")
+ .author("Steve P.")
+ .version("2.31.2")
+ .args(&[
+ Arg::with_name("cfg")
+ .short("c")
+ .long("config")
+ .hidden_short_help(true)
+ .help("Some help text describing the --config arg"),
+ Arg::with_name("visible")
+ .short("v")
+ .long("visible")
+ .help("This text should be visible")]);
+
+ assert!(test::compare_output(app, "test --help", HIDDEN_SHORT_ARGS_LONG_HELP, false));
+}
+
+static HIDDEN_LONG_ARGS: &'static str = "test 2.31.2
+Steve P.
+hides long args
+
+USAGE:
+ test [FLAGS]
+
+FLAGS:
+ -h, --help
+ Prints help information
+
+ -V, --version
+ Prints version information
+
+ -v, --visible
+ This text should be visible";
+
+#[test]
+fn hidden_long_args() {
+ let app = App::new("test")
+ .about("hides long args")
+ .author("Steve P.")
+ .version("2.31.2")
+ .args(&[
+ Arg::with_name("cfg")
+ .short("c")
+ .long("config")
+ .hidden_long_help(true)
+ .help("Some help text describing the --config arg"),
+ Arg::with_name("visible")
+ .short("v")
+ .long("visible")
+ .help("This text should be visible")]);
+
+ assert!(test::compare_output(app, "test --help", HIDDEN_LONG_ARGS, false));
+}
+
+static HIDDEN_LONG_ARGS_SHORT_HELP: &'static str = "test 2.31.2
+Steve P.
+hides long args
+
+USAGE:
+ test [FLAGS]
+
+FLAGS:
+ -c, --config Some help text describing the --config arg
+ -h, --help Prints help information
+ -V, --version Prints version information
+ -v, --visible This text should be visible";
+
+#[test]
+fn hidden_long_args_short_help() {
+ let app = App::new("test")
+ .about("hides long args")
+ .author("Steve P.")
+ .version("2.31.2")
+ .args(&[
+ Arg::with_name("cfg")
+ .short("c")
+ .long("config")
+ .hidden_long_help(true)
+ .help("Some help text describing the --config arg"),
+ Arg::with_name("visible")
+ .short("v")
+ .long("visible")
+ .help("This text should be visible")]);
+
+ assert!(test::compare_output(app, "test -h", HIDDEN_LONG_ARGS_SHORT_HELP, false));
+}
diff --git a/clap/tests/indices.rs b/clap/tests/indices.rs
new file mode 100644
index 0000000..910529e
--- /dev/null
+++ b/clap/tests/indices.rs
@@ -0,0 +1,175 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, Arg};
+
+#[test]
+fn indices_mult_opts() {
+ let m = App::new("ind")
+ .arg(Arg::with_name("exclude")
+ .short("e")
+ .takes_value(true)
+ .multiple(true))
+ .arg(Arg::with_name("include")
+ .short("i")
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from(vec!["ind", "-e", "A", "B", "-i", "B", "C", "-e", "C"]);
+
+ assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[2, 3, 8]);
+ assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[5, 6]);
+}
+
+#[test]
+fn index_mult_opts() {
+ let m = App::new("ind")
+ .arg(Arg::with_name("exclude")
+ .short("e")
+ .takes_value(true)
+ .multiple(true))
+ .arg(Arg::with_name("include")
+ .short("i")
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from(vec!["ind", "-e", "A", "B", "-i", "B", "C", "-e", "C"]);
+
+ assert_eq!(m.index_of("exclude"), Some(2));
+ assert_eq!(m.index_of("include"), Some(5));
+}
+
+#[test]
+fn index_flag() {
+ let m = App::new("ind")
+ .arg(Arg::with_name("exclude")
+ .short("e"))
+ .arg(Arg::with_name("include")
+ .short("i"))
+ .get_matches_from(vec!["ind", "-e", "-i"]);
+
+ assert_eq!(m.index_of("exclude"), Some(1));
+ assert_eq!(m.index_of("include"), Some(2));
+}
+
+#[test]
+fn index_flags() {
+ let m = App::new("ind")
+ .arg(Arg::with_name("exclude")
+ .short("e")
+ .multiple(true))
+ .arg(Arg::with_name("include")
+ .short("i")
+ .multiple(true))
+ .get_matches_from(vec!["ind", "-e", "-i", "-e", "-e", "-i"]);
+
+ assert_eq!(m.index_of("exclude"), Some(1));
+ assert_eq!(m.index_of("include"), Some(2));
+}
+
+#[test]
+fn indices_mult_flags() {
+ let m = App::new("ind")
+ .arg(Arg::with_name("exclude")
+ .short("e")
+ .multiple(true))
+ .arg(Arg::with_name("include")
+ .short("i")
+ .multiple(true))
+ .get_matches_from(vec!["ind", "-e", "-i", "-e", "-e", "-i"]);
+
+ assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[1, 3, 4]);
+ assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[2, 5]);
+}
+
+#[test]
+fn indices_mult_flags_combined() {
+ let m = App::new("ind")
+ .arg(Arg::with_name("exclude")
+ .short("e")
+ .multiple(true))
+ .arg(Arg::with_name("include")
+ .short("i")
+ .multiple(true))
+ .get_matches_from(vec!["ind", "-eieei"]);
+
+ assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[1, 3, 4]);
+ assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[2, 5]);
+}
+
+#[test]
+fn indices_mult_flags_opt_combined() {
+ let m = App::new("ind")
+ .arg(Arg::with_name("exclude")
+ .short("e")
+ .multiple(true))
+ .arg(Arg::with_name("include")
+ .short("i")
+ .multiple(true))
+ .arg(Arg::with_name("option")
+ .short("o")
+ .takes_value(true))
+ .get_matches_from(vec!["ind", "-eieeio", "val"]);
+
+ assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[1, 3, 4]);
+ assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[2, 5]);
+ assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[7]);
+}
+
+#[test]
+fn indices_mult_flags_opt_combined_eq() {
+ let m = App::new("ind")
+ .arg(Arg::with_name("exclude")
+ .short("e")
+ .multiple(true))
+ .arg(Arg::with_name("include")
+ .short("i")
+ .multiple(true))
+ .arg(Arg::with_name("option")
+ .short("o")
+ .takes_value(true))
+ .get_matches_from(vec!["ind", "-eieeio=val"]);
+
+ assert_eq!(m.indices_of("exclude").unwrap().collect::<Vec<_>>(), &[1, 3, 4]);
+ assert_eq!(m.indices_of("include").unwrap().collect::<Vec<_>>(), &[2, 5]);
+ assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[7]);
+}
+
+#[test]
+fn indices_mult_opt_value_delim_eq() {
+ let m = App::new("myapp")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .takes_value(true)
+ .use_delimiter(true)
+ .multiple(true))
+ .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
+ assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
+}
+
+#[test]
+fn indices_mult_opt_value_no_delim_eq() {
+ let m = App::new("myapp")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
+ assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]);
+}
+
+#[test]
+fn indices_mult_opt_mult_flag() {
+ let m = App::new("myapp")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .takes_value(true)
+ .multiple(true))
+ .arg(Arg::with_name("flag")
+ .short("f")
+ .multiple(true))
+ .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]);
+
+ assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
+ assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[3, 6]);
+}
diff --git a/clap/tests/macros.rs b/clap/tests/macros.rs
new file mode 100755
index 0000000..0cdcb52
--- /dev/null
+++ b/clap/tests/macros.rs
@@ -0,0 +1,391 @@
+#[macro_use]
+extern crate clap;
+
+use clap::ErrorKind;
+
+#[test]
+fn basic() {
+ clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg opt: -o --option +takes_value ... "tests options")
+ (@arg positional: index(1) "tests positionals")
+ (@arg flag: -f --flag ... +global "tests flags")
+ (@arg flag2: -F conflicts_with[flag] requires[option2]
+ "tests flags with exclusions")
+ (@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
+ "tests long options with exclusions")
+ (@arg positional2: index(2) "tests positionals with exclusions")
+ (@arg option3: -O --Option +takes_value possible_value[fast slow]
+ "tests options with specific value sets")
+ (@arg positional3: index(3) ... possible_value[vi emacs]
+ "tests positionals with specific values")
+ (@arg multvals: --multvals +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
+ (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
+ (@subcommand subcmd =>
+ (about: "tests subcommands")
+ (version: "0.1")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg scoption: -o --option ... +takes_value "tests options")
+ (@arg scpositional: index(1) "tests positionals"))
+ );
+}
+
+#[test]
+fn quoted_app_name() {
+ let app = clap_app!(("app name with spaces-and-hyphens") =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg opt: -o --option +takes_value ... "tests options")
+ (@arg positional: index(1) "tests positionals")
+ (@arg flag: -f --flag ... +global "tests flags")
+ (@arg flag2: -F conflicts_with[flag] requires[option2]
+ "tests flags with exclusions")
+ (@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
+ "tests long options with exclusions")
+ (@arg positional2: index(2) "tests positionals with exclusions")
+ (@arg option3: -O --Option +takes_value possible_value[fast slow]
+ "tests options with specific value sets")
+ (@arg positional3: index(3) ... possible_value[vi emacs]
+ "tests positionals with specific values")
+ (@arg multvals: --multvals +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
+ (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
+ (@subcommand subcmd =>
+ (about: "tests subcommands")
+ (version: "0.1")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg scoption: -o --option ... +takes_value "tests options")
+ (@arg scpositional: index(1) "tests positionals"))
+ );
+
+ assert_eq!(app.p.meta.name, "app name with spaces-and-hyphens");
+
+ let mut help_text = vec![];
+ app.write_help(&mut help_text).expect("Could not write help text.");
+ let help_text = String::from_utf8(help_text).expect("Help text is not valid utf-8");
+ assert!(help_text.starts_with("app name with spaces-and-hyphens 0.1\n"));
+}
+
+#[test]
+fn quoted_arg_long_name() {
+ let app = clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg opt: -o --option +takes_value ... "tests options")
+ (@arg positional: index(1) "tests positionals")
+ (@arg flag: -f --flag ... +global "tests flags")
+ (@arg flag2: -F conflicts_with[flag] requires[option2]
+ "tests flags with exclusions")
+ (@arg option2: --("long-option-2") conflicts_with[option] requires[positional2]
+ "tests long options with exclusions")
+ (@arg positional2: index(2) "tests positionals with exclusions")
+ (@arg option3: -O --Option +takes_value possible_value[fast slow]
+ "tests options with specific value sets")
+ (@arg positional3: index(3) ... possible_value[vi emacs]
+ "tests positionals with specific values")
+ (@arg multvals: --multvals +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
+ (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
+ (@subcommand subcmd =>
+ (about: "tests subcommands")
+ (version: "0.1")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg scoption: -o --option ... +takes_value "tests options")
+ (@arg scpositional: index(1) "tests positionals"))
+ );
+
+ let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
+ .expect("Expected to successfully match the given args.");
+ assert!(matches.is_present("option2"));
+}
+
+#[test]
+fn quoted_arg_name() {
+ let app = clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg opt: -o --option +takes_value ... "tests options")
+ (@arg ("positional-arg"): index(1) "tests positionals")
+ (@arg flag: -f --flag ... +global "tests flags")
+ (@arg flag2: -F conflicts_with[flag] requires[option2]
+ "tests flags with exclusions")
+ (@arg option2: --("long-option-2") conflicts_with[option] requires[positional2]
+ "tests long options with exclusions")
+ (@arg positional2: index(2) "tests positionals with exclusions")
+ (@arg option3: -O --Option +takes_value possible_value[fast slow]
+ "tests options with specific value sets")
+ (@arg ("positional-3"): index(3) ... possible_value[vi emacs]
+ "tests positionals with specific values")
+ (@arg multvals: --multvals +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
+ "Tests multiple values, not mult occs")
+ (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
+ (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
+ (@subcommand subcmd =>
+ (about: "tests subcommands")
+ (version: "0.1")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@arg scoption: -o --option ... +takes_value "tests options")
+ (@arg scpositional: index(1) "tests positionals"))
+ );
+
+ let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
+ .expect("Expected to successfully match the given args.");
+ assert!(matches.is_present("option2"));
+}
+
+#[test]
+fn group_macro() {
+ let app = clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@group difficulty =>
+ (@arg hard: -h --hard "Sets hard mode")
+ (@arg normal: -n --normal "Sets normal mode")
+ (@arg easy: -e --easy "Sets easy mode")
+ )
+ );
+
+ let result = app.get_matches_from_safe(vec!["bin_name", "--hard"]);
+ assert!(result.is_ok());
+ let matches = result.expect("Expected to successfully match the given args.");
+ assert!(matches.is_present("difficulty"));
+ assert!(matches.is_present("hard"));
+}
+
+#[test]
+fn group_macro_set_multiple() {
+ let app = clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@group difficulty +multiple =>
+ (@arg hard: -h --hard "Sets hard mode")
+ (@arg normal: -n --normal "Sets normal mode")
+ (@arg easy: -e --easy "Sets easy mode")
+ )
+ );
+
+ let result = app.get_matches_from_safe(vec!["bin_name", "--hard", "--easy"]);
+ assert!(result.is_ok());
+ let matches = result.expect("Expected to successfully match the given args.");
+ assert!(matches.is_present("difficulty"));
+ assert!(matches.is_present("hard"));
+ assert!(matches.is_present("easy"));
+ assert!(!matches.is_present("normal"));
+}
+
+#[test]
+fn group_macro_set_not_multiple() {
+ let app = clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@group difficulty !multiple =>
+ (@arg hard: -h --hard "Sets hard mode")
+ (@arg normal: -n --normal "Sets normal mode")
+ (@arg easy: -e --easy "Sets easy mode")
+ )
+ );
+
+ let result = app.get_matches_from_safe(vec!["bin_name", "--hard", "--easy"]);
+ assert!(result.is_err());
+ let err = result.unwrap_err();
+ assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+}
+
+#[test]
+fn group_macro_set_required() {
+ let app = clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@group difficulty +required =>
+ (@arg hard: -h --hard "Sets hard mode")
+ (@arg normal: -n --normal "Sets normal mode")
+ (@arg easy: -e --easy "Sets easy mode")
+ )
+ );
+
+ let result = app.get_matches_from_safe(vec!["bin_name"]);
+ assert!(result.is_err());
+ let err = result.unwrap_err();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn group_macro_set_not_required() {
+ let app = clap_app!(claptests =>
+ (version: "0.1")
+ (about: "tests clap library")
+ (author: "Kevin K. <kbknapp@gmail.com>")
+ (@group difficulty !required =>
+ (@arg hard: -h --hard "Sets hard mode")
+ (@arg normal: -n --normal "Sets normal mode")
+ (@arg easy: -e --easy "Sets easy mode")
+ )
+ );
+
+ let result = app.get_matches_from_safe(vec!["bin_name"]);
+ assert!(result.is_ok());
+ let matches = result.expect("Expected to successfully match the given args.");
+ assert!(!matches.is_present("difficulty"));
+}
+
+#[test]
+fn multiarg() {
+ let app = || clap_app!(
+ claptests =>
+ (@arg flag: --flag "value")
+ (@arg multiarg: --multiarg
+ default_value("flag-unset") default_value_if("flag", None, "flag-set")
+ "multiarg")
+ (@arg multiarg2: --multiarg2
+ default_value("flag-unset") default_value_if("flag", None, "flag-set",)
+ "multiarg2")
+ );
+
+ let matches = app()
+ .get_matches_from_safe(vec!["bin_name"])
+ .expect("match failed");
+ assert_eq!(matches.value_of("multiarg"), Some("flag-unset"));
+ assert_eq!(matches.value_of("multiarg2"), Some("flag-unset"));
+
+ let matches = app()
+ .get_matches_from_safe(vec!["bin_name", "--flag"])
+ .expect("match failed");
+ assert_eq!(matches.value_of("multiarg"), Some("flag-set"));
+ assert_eq!(matches.value_of("multiarg2"), Some("flag-set"));
+}
+
+#[test]
+fn arg_enum() {
+ // Helper macros to avoid repetition
+ macro_rules! test_greek {
+ ($arg_enum:item, $tests:block) => {{
+ $arg_enum
+ // FromStr implementation
+ assert!("Charlie".parse::<Greek>().is_err());
+ // Display implementation
+ assert_eq!(format!("{}", Greek::Alpha), "Alpha");
+ assert_eq!(format!("{}", Greek::Bravo), "Bravo");
+ // fn variants()
+ assert_eq!(Greek::variants(), ["Alpha", "Bravo"]);
+ // rest of tests
+ $tests
+ }};
+ }
+ macro_rules! test_greek_no_meta {
+ {$arg_enum:item} => {
+ test_greek!($arg_enum, {
+ // FromStr implementation
+ assert!("Alpha".parse::<Greek>().is_ok());
+ assert!("Bravo".parse::<Greek>().is_ok());
+ })
+ };
+ }
+ macro_rules! test_greek_meta {
+ {$arg_enum:item} => {
+ test_greek!($arg_enum, {
+ // FromStr implementation
+ assert_eq!("Alpha".parse::<Greek>(), Ok(Greek::Alpha));
+ assert_eq!("Bravo".parse::<Greek>(), Ok(Greek::Bravo));
+ })
+ };
+ }
+
+ // Tests for each pattern
+ // meta NO, pub NO, trailing comma NO
+ test_greek_no_meta!{
+ arg_enum!{
+ enum Greek {
+ Alpha,
+ Bravo
+ }
+ }
+ };
+ // meta NO, pub NO, trailing comma YES
+ test_greek_no_meta!{
+ arg_enum!{
+ enum Greek {
+ Alpha,
+ Bravo,
+ }
+ }
+ };
+ // meta NO, pub YES, trailing comma NO
+ test_greek_no_meta!{
+ arg_enum!{
+ pub enum Greek {
+ Alpha,
+ Bravo
+ }
+ }
+ };
+ // meta NO, pub YES, trailing comma YES
+ test_greek_no_meta!{
+ arg_enum!{
+ pub enum Greek {
+ Alpha,
+ Bravo,
+ }
+ }
+ };
+ // meta YES, pub NO, trailing comma NO
+ test_greek_meta!{
+ arg_enum!{
+ #[derive(Debug, PartialEq, Copy, Clone)]
+ enum Greek {
+ Alpha,
+ Bravo
+ }
+ }
+ };
+ // meta YES, pub NO, trailing comma YES
+ test_greek_meta!{
+ arg_enum!{
+ #[derive(Debug, PartialEq, Copy, Clone)]
+ enum Greek {
+ Alpha,
+ Bravo,
+ }
+ }
+ };
+ // meta YES, pub YES, trailing comma NO
+ test_greek_meta!{
+ arg_enum!{
+ #[derive(Debug, PartialEq, Copy, Clone)]
+ pub enum Greek {
+ Alpha,
+ Bravo
+ }
+ }
+ };
+ // meta YES, pub YES, trailing comma YES
+ test_greek_meta!{
+ arg_enum!{
+ #[derive(Debug, PartialEq, Copy, Clone)]
+ pub enum Greek {
+ Alpha,
+ Bravo,
+ }
+ }
+ };
+}
diff --git a/clap/tests/multiple_occurrences.rs b/clap/tests/multiple_occurrences.rs
new file mode 100644
index 0000000..2f92fb1
--- /dev/null
+++ b/clap/tests/multiple_occurrences.rs
@@ -0,0 +1,75 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+#[test]
+fn multiple_occurrences_of_flags_long() {
+ let m = App::new("mo_flags_long")
+ .arg(Arg::from_usage("--multflag 'allowed multiple flag'")
+ .multiple(true))
+ .arg(Arg::from_usage("--flag 'disallowed multiple flag'"))
+ .get_matches_from(vec![
+ "",
+ "--multflag",
+ "--flag",
+ "--multflag"
+ ]);
+ assert!(m.is_present("multflag"));
+ assert_eq!(m.occurrences_of("multflag"), 2);
+ assert!(m.is_present("flag"));
+ assert_eq!(m.occurrences_of("flag"), 1)
+}
+
+#[test]
+fn multiple_occurrences_of_flags_short() {
+ let m = App::new("mo_flags_short")
+ .arg(Arg::from_usage("-m --multflag 'allowed multiple flag'")
+ .multiple(true))
+ .arg(Arg::from_usage("-f --flag 'disallowed multiple flag'"))
+ .get_matches_from(vec![
+ "",
+ "-m",
+ "-f",
+ "-m"
+ ]);
+ assert!(m.is_present("multflag"));
+ assert_eq!(m.occurrences_of("multflag"), 2);
+ assert!(m.is_present("flag"));
+ assert_eq!(m.occurrences_of("flag"), 1);
+}
+
+#[test]
+fn multiple_occurrences_of_flags_mixed() {
+ let m = App::new("mo_flags_mixed")
+ .arg(Arg::from_usage("-m, --multflag1 'allowed multiple flag'")
+ .multiple(true))
+ .arg(Arg::from_usage("-n, --multflag2 'another allowed multiple flag'")
+ .multiple(true))
+ .arg(Arg::from_usage("-f, --flag 'disallowed multiple flag'"))
+ .get_matches_from(vec![
+ "",
+ "-m",
+ "-f",
+ "-n",
+ "--multflag1",
+ "-m",
+ "--multflag2"
+ ]);
+ assert!(m.is_present("multflag1"));
+ assert_eq!(m.occurrences_of("multflag1"), 3);
+ assert!(m.is_present("multflag2"));
+ assert_eq!(m.occurrences_of("multflag2"), 2);
+ assert!(m.is_present("flag"));
+ assert_eq!(m.occurrences_of("flag"), 1);
+}
+
+#[test]
+fn multiple_occurrences_of_flags_large_quantity() {
+ let args : Vec<&str> = vec![""].into_iter().chain(vec!["-m"; 1024].into_iter()).collect();
+ let m = App::new("mo_flags_larg_qty")
+ .arg(Arg::from_usage("-m --multflag 'allowed multiple flag'")
+ .multiple(true))
+ .get_matches_from(args);
+ assert!(m.is_present("multflag"));
+ assert_eq!(m.occurrences_of("multflag"), 1024);
+}
diff --git a/clap/tests/multiple_values.rs b/clap/tests/multiple_values.rs
new file mode 100644
index 0000000..551aff1
--- /dev/null
+++ b/clap/tests/multiple_values.rs
@@ -0,0 +1,1122 @@
+extern crate clap;
+
+use clap::{App, Arg, ErrorKind, SubCommand};
+
+#[test]
+fn option_long() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "--option", "val1",
+ "--option", "val2",
+ "--option", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 3);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn option_short() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ "-o", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 3);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn option_mixed() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "--option", "val2",
+ "--option", "val3",
+ "-o", "val4",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 4);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4"]);
+}
+
+#[test]
+fn option_exact_exact() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ "-o", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 3);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn option_exact_exact_not_mult() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .number_of_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1", "val2", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn option_exact_exact_mult() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1", "val2", "val3",
+ "-o", "val4", "val5", "val6",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 2);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4", "val5", "val6"]);
+}
+
+#[test]
+fn option_exact_less() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ ]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues);
+}
+
+#[test]
+fn option_exact_more() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ "-o", "val3",
+ "-o", "val4",
+ ]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues);
+}
+
+#[test]
+fn option_min_exact() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .min_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ "-o", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 3);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn option_min_less() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .min_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ ]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::TooFewValues);
+}
+
+#[test]
+fn option_short_min_more_mult_occurs() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("arg")
+ .required(true))
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .min_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "pos",
+ "-o", "val1",
+ "-o", "val2",
+ "-o", "val3",
+ "-o", "val4",
+ ]);
+
+ let m = m.map_err(|e| println!("failed to unwrap err with error kind {:?}", e.kind)).unwrap();
+
+ assert!(m.is_present("option"));
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("option"), 4);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4"]);
+ assert_eq!(m.value_of("arg"), Some("pos"));
+}
+
+#[test]
+fn option_short_min_more_single_occur() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("arg")
+ .required(true))
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .min_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "pos",
+ "-o", "val1",
+ "val2",
+ "val3",
+ "val4",
+ ]);
+
+ let m = m.map_err(|e| println!("failed to unwrap err with error kind {:#?}", e)).unwrap();
+
+ assert!(m.is_present("option"));
+ assert!(m.is_present("arg"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4"]);
+ assert_eq!(m.value_of("arg"), Some("pos"));
+}
+
+#[test]
+fn option_max_exact() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .max_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ "-o", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 3);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn option_max_less() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .max_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 2);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2"]);
+}
+
+#[test]
+fn option_max_more() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true)
+ .max_values(3))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1",
+ "-o", "val2",
+ "-o", "val3",
+ "-o", "val4",
+ ]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::TooManyValues);
+}
+
+#[test]
+fn positional() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .multiple(true))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("pos"));
+ assert_eq!(m.occurrences_of("pos"), 3);
+ assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn positional_exact_exact() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .number_of_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("pos"));
+ assert_eq!(m.occurrences_of("pos"), 3);
+ assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn positional_exact_less() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .number_of_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues);
+}
+
+#[test]
+fn positional_exact_more() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .number_of_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3", "val4"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::WrongNumberOfValues);
+}
+
+#[test]
+fn positional_min_exact() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .min_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("pos"));
+ assert_eq!(m.occurrences_of("pos"), 3);
+ assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn positional_min_less() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .min_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::TooFewValues);
+}
+
+#[test]
+fn positional_min_more() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .min_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3", "val4"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("pos"));
+ assert_eq!(m.occurrences_of("pos"), 4);
+ assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3", "val4"]);
+}
+
+#[test]
+fn positional_max_exact() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .max_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("pos"));
+ assert_eq!(m.occurrences_of("pos"), 3);
+ assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn positional_max_less() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .max_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("pos"));
+ assert_eq!(m.occurrences_of("pos"), 2);
+ assert_eq!(m.values_of("pos").unwrap().collect::<Vec<_>>(), ["val1", "val2"]);
+}
+
+#[test]
+fn positional_max_more() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("pos")
+ .help("multiple positionals")
+ .max_values(3))
+ .get_matches_from_safe(vec!["myprog", "val1", "val2", "val3", "val4"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::TooManyValues);
+}
+
+#[test]
+fn sep_long_equals() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .use_delimiter(true)
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "--option=val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn sep_long_space() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .use_delimiter(true)
+ .help("multiple options")
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "--option",
+ "val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn sep_short_equals() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .use_delimiter(true)
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-o=val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn sep_short_space() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .use_delimiter(true)
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-o",
+ "val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn sep_short_no_space() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .help("multiple options")
+ .use_delimiter(true)
+ .takes_value(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "-oval1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn sep_positional() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .help("multiple options")
+ .use_delimiter(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "",
+ "val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn different_sep() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .help("multiple options")
+ .takes_value(true)
+ .value_delimiter(";"))
+ .get_matches_from_safe(vec![
+ "",
+ "--option=val1;val2;val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn different_sep_positional() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .help("multiple options")
+ .value_delimiter(";"))
+ .get_matches_from_safe(vec![
+ "",
+ "val1;val2;val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"]);
+}
+
+#[test]
+fn no_sep() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .help("multiple options")
+ .takes_value(true)
+ .use_delimiter(false))
+ .get_matches_from_safe(vec![
+ "",
+ "--option=val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
+}
+
+#[test]
+fn no_sep_positional() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .help("multiple options")
+ .use_delimiter(false))
+ .get_matches_from_safe(vec![
+ "",
+ "val1,val2,val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3");
+}
+
+#[test]
+fn req_delimiter_long() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .multiple(true)
+ .use_delimiter(true)
+ .require_delimiter(true)
+ .takes_value(true))
+ .arg(Arg::with_name("args")
+ .multiple(true)
+ .index(1))
+ .get_matches_from_safe(vec![
+ "",
+ "--option", "val1", "val2", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]);
+ assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]);
+}
+
+#[test]
+fn req_delimiter_long_with_equal() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .multiple(true)
+ .use_delimiter(true)
+ .require_delimiter(true)
+ .takes_value(true))
+ .arg(Arg::with_name("args")
+ .multiple(true)
+ .index(1))
+ .get_matches_from_safe(vec![
+ "",
+ "--option=val1", "val2", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]);
+ assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]);
+}
+
+#[test]
+fn req_delimiter_short_with_space() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .multiple(true)
+ .use_delimiter(true)
+ .require_delimiter(true)
+ .takes_value(true))
+ .arg(Arg::with_name("args")
+ .multiple(true)
+ .index(1))
+ .get_matches_from_safe(vec![
+ "",
+ "-o", "val1", "val2", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]);
+ assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]);
+}
+
+#[test]
+fn req_delimiter_short_with_no_space() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("o")
+ .multiple(true)
+ .use_delimiter(true)
+ .require_delimiter(true)
+ .takes_value(true))
+ .arg(Arg::with_name("args")
+ .multiple(true)
+ .index(1))
+ .get_matches_from_safe(vec![
+ "",
+ "-oval1", "val2", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]);
+ assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]);
+}
+
+#[test]
+fn req_delimiter_short_with_equal() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .short("option")
+ .multiple(true)
+ .use_delimiter(true)
+ .require_delimiter(true)
+ .takes_value(true))
+ .arg(Arg::with_name("args")
+ .multiple(true)
+ .index(1))
+ .get_matches_from_safe(vec![
+ "",
+ "-o=val1", "val2", "val3",
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 1);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), &["val1"]);
+ assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(), &["val2", "val3"]);
+}
+
+#[test]
+fn req_delimiter_complex() {
+ let m = App::new("multiple_values")
+ .arg(Arg::with_name("option")
+ .long("option")
+ .short("o")
+ .multiple(true)
+ .use_delimiter(true)
+ .require_delimiter(true)
+ .takes_value(true))
+ .arg(Arg::with_name("args")
+ .multiple(true)
+ .index(1))
+ .get_matches_from_safe(vec![
+ "",
+ "val1",
+ "-oval2", "val3",
+ "-o", "val4", "val5",
+ "-o=val6", "val7",
+ "--option=val8", "val9",
+ "--option", "val10", "val11",
+ "-oval12,val13", "val14",
+ "-o", "val15,val16", "val17",
+ "-o=val18,val19", "val20",
+ "--option=val21,val22", "val23",
+ "--option", "val24,val25", "val26"
+ ]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.occurrences_of("option"), 10);
+ assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(),
+ &["val2", "val4", "val6", "val8", "val10", "val12", "val13", "val15",
+ "val16", "val18", "val19", "val21", "val22", "val24", "val25"]);
+ assert_eq!(m.values_of("args").unwrap().collect::<Vec<_>>(),
+ &["val1", "val3", "val5", "val7", "val9", "val11", "val14", "val17",
+ "val20", "val23", "val26"]);
+}
+
+#[test]
+#[should_panic]
+fn low_index_positional_not_required() {
+ let _ = App::new("lip")
+ .arg(Arg::with_name("files")
+ .index(1)
+ .required(true)
+ .multiple(true))
+ .arg(Arg::with_name("target")
+ .index(2))
+ .get_matches_from_safe(vec![
+ "lip",
+ "file1", "file2",
+ "file3", "target",
+ ]);
+}
+
+#[test]
+#[should_panic]
+fn low_index_positional_last_multiple_too() {
+ let _ = App::new("lip")
+ .arg(Arg::with_name("files")
+ .index(1)
+ .required(true)
+ .multiple(true))
+ .arg(Arg::with_name("target")
+ .index(2)
+ .required(true)
+ .multiple(true))
+ .get_matches_from_safe(vec![
+ "lip",
+ "file1", "file2",
+ "file3", "target",
+ ]);
+}
+
+#[test]
+#[should_panic]
+fn low_index_positional_too_far_back() {
+ let _ = App::new("lip")
+ .arg(Arg::with_name("files")
+ .index(1)
+ .required(true)
+ .multiple(true))
+ .arg(Arg::with_name("target")
+ .required(true)
+ .index(2))
+ .arg(Arg::with_name("target2")
+ .required(true)
+ .index(3))
+ .get_matches_from_safe(vec![
+ "lip",
+ "file1", "file2",
+ "file3", "target",
+ ]);
+}
+
+#[test]
+fn low_index_positional() {
+ let m = App::new("lip")
+ .arg(Arg::with_name("files")
+ .index(1)
+ .required(true)
+ .multiple(true))
+ .arg(Arg::with_name("target")
+ .index(2)
+ .required(true))
+ .get_matches_from_safe(vec![
+ "lip",
+ "file1", "file2",
+ "file3", "target",
+ ]);
+
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+
+ assert!(m.is_present("files"));
+ assert_eq!(m.occurrences_of("files"), 3);
+ assert!(m.is_present("target"));
+ assert_eq!(m.occurrences_of("target"), 1);
+ assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
+ assert_eq!(m.value_of("target").unwrap(), "target");
+}
+
+#[test]
+fn low_index_positional_in_subcmd() {
+ let m = App::new("lip")
+ .subcommand(SubCommand::with_name("test")
+ .arg(Arg::with_name("files")
+ .index(1)
+ .required(true)
+ .multiple(true))
+ .arg(Arg::with_name("target")
+ .index(2)
+ .required(true)))
+ .get_matches_from_safe(vec![
+ "lip", "test",
+ "file1", "file2",
+ "file3", "target"
+ ]);
+
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+ let sm = m.subcommand_matches("test").unwrap();
+
+ assert!(sm.is_present("files"));
+ assert_eq!(sm.occurrences_of("files"), 3);
+ assert!(sm.is_present("target"));
+ assert_eq!(sm.occurrences_of("target"), 1);
+ assert_eq!(sm.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
+ assert_eq!(sm.value_of("target").unwrap(), "target");
+}
+
+#[test]
+fn low_index_positional_with_option() {
+ let m = App::new("lip")
+ .arg(Arg::with_name("files")
+ .required(true)
+ .index(1)
+ .multiple(true))
+ .arg(Arg::with_name("target")
+ .index(2)
+ .required(true))
+ .arg(Arg::with_name("opt")
+ .long("option")
+ .takes_value(true))
+ .get_matches_from_safe(vec![
+ "lip",
+ "file1", "file2",
+ "file3", "target",
+ "--option", "test"
+ ]);
+
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+
+ assert!(m.is_present("files"));
+ assert_eq!(m.occurrences_of("files"), 3);
+ assert!(m.is_present("target"));
+ assert_eq!(m.occurrences_of("target"), 1);
+ assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
+ assert_eq!(m.value_of("target").unwrap(), "target");
+ assert_eq!(m.value_of("opt").unwrap(), "test");
+}
+
+#[test]
+fn low_index_positional_with_flag() {
+ let m = App::new("lip")
+ .arg(Arg::with_name("files")
+ .index(1)
+ .required(true)
+ .multiple(true))
+ .arg(Arg::with_name("target")
+ .index(2)
+ .required(true))
+ .arg(Arg::with_name("flg")
+ .long("flag"))
+ .get_matches_from_safe(vec![
+ "lip",
+ "file1", "file2",
+ "file3", "target",
+ "--flag"
+ ]);
+
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+
+ assert!(m.is_present("files"));
+ assert_eq!(m.occurrences_of("files"), 3);
+ assert!(m.is_present("target"));
+ assert_eq!(m.occurrences_of("target"), 1);
+ assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["file1", "file2", "file3"]);
+ assert_eq!(m.value_of("target").unwrap(), "target");
+ assert!(m.is_present("flg"));
+}
+
+#[test]
+fn multiple_value_terminator_option() {
+ let m = App::new("lip")
+ .arg(Arg::with_name("files")
+ .short("f")
+ .value_terminator(";")
+ .multiple(true))
+ .arg(Arg::with_name("other"))
+ .get_matches_from_safe(vec![
+ "lip",
+ "-f", "val1", "val2", ";",
+ "otherval"
+ ]);
+
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+
+ assert!(m.is_present("other"));
+ assert_eq!(m.occurrences_of("other"), 1);
+ assert!(m.is_present("files"));
+ assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["val1", "val2"]);
+ assert_eq!(m.value_of("other"), Some("otherval"));
+}
+
+#[test]
+fn multiple_value_terminator_option_other_arg() {
+ let m = App::new("lip")
+ .arg(Arg::with_name("files")
+ .short("f")
+ .value_terminator(";")
+ .multiple(true))
+ .arg(Arg::with_name("other"))
+ .arg(Arg::with_name("flag")
+ .short("-F"))
+ .get_matches_from_safe(vec![
+ "lip",
+ "-f", "val1", "val2",
+ "-F",
+ "otherval"
+ ]);
+
+ assert!(m.is_ok(), "{:?}", m.unwrap_err().kind);
+ let m = m.unwrap();
+
+ assert!(m.is_present("other"));
+ assert!(m.is_present("files"));
+ assert_eq!(m.values_of("files").unwrap().collect::<Vec<_>>(), ["val1", "val2"]);
+ assert_eq!(m.value_of("other"), Some("otherval"));
+ assert!(m.is_present("flag"));
+}
+
+#[test]
+fn multiple_vals_with_hyphen() {
+ let res = App::new("do")
+ .arg(Arg::with_name("cmds")
+ .multiple(true)
+ .allow_hyphen_values(true)
+ .value_terminator(";"))
+ .arg(Arg::with_name("location"))
+ .get_matches_from_safe(vec!["do", "find", "-type", "f", "-name", "special", ";", "/home/clap"]);
+ assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
+
+ let m = res.unwrap();
+ let cmds: Vec<_> = m.values_of("cmds").unwrap().collect();
+ assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]);
+ assert_eq!(m.value_of("location"), Some("/home/clap"));
+}
diff --git a/clap/tests/opts.rs b/clap/tests/opts.rs
new file mode 100644
index 0000000..a9029ac
--- /dev/null
+++ b/clap/tests/opts.rs
@@ -0,0 +1,461 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, ArgMatches, Arg, ErrorKind};
+
+#[cfg(feature = "suggestions")]
+static DYM: &'static str = "error: Found argument '--optio' which wasn't expected, or isn't valid in this context
+\tDid you mean --option?
+
+USAGE:
+ clap-test --option <opt>...
+
+For more information try --help";
+
+#[test]
+fn require_equals_fail() {
+ let res = App::new("prog")
+ .arg(Arg::with_name("cfg")
+ .require_equals(true)
+ .takes_value(true)
+ .long("config"))
+ .get_matches_from_safe(vec![
+ "prog", "--config", "file.conf"
+ ]);
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
+}
+
+#[test]
+fn require_equals_min_values_zero() {
+ let res = App::new("prog")
+ .arg(Arg::with_name("cfg")
+ .require_equals(true)
+ .takes_value(true)
+ .min_values(0)
+ .long("config"))
+ .arg(Arg::with_name("cmd"))
+ .get_matches_from_safe(vec![
+ "prog", "--config", "cmd"
+ ]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("cfg"));
+ assert_eq!(m.value_of("cmd"), Some("cmd"));
+}
+
+#[test]
+fn double_hyphen_as_value() {
+ let res = App::new("prog")
+ .arg(Arg::with_name("cfg")
+ .takes_value(true)
+ .allow_hyphen_values(true)
+ .long("config"))
+ .get_matches_from_safe(vec![
+ "prog", "--config", "--"
+ ]);
+ assert!(res.is_ok(), "{:?}", res);
+ assert_eq!(res.unwrap().value_of("cfg"), Some("--"));
+}
+
+#[test]
+fn require_equals_no_empty_values_fail() {
+ let res = App::new("prog")
+ .arg(Arg::with_name("cfg")
+ .require_equals(true)
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("some"))
+ .get_matches_from_safe(vec![
+ "prog", "--config=", "file.conf"
+ ]);
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
+}
+
+#[test]
+fn require_equals_empty_vals_pass() {
+ let res = App::new("prog")
+ .arg(Arg::with_name("cfg")
+ .require_equals(true)
+ .takes_value(true)
+ .empty_values(true)
+ .long("config"))
+ .get_matches_from_safe(vec![
+ "prog", "--config="
+ ]);
+ assert!(res.is_ok());
+}
+
+#[test]
+fn require_equals_pass() {
+ let res = App::new("prog")
+ .arg(Arg::with_name("cfg")
+ .require_equals(true)
+ .takes_value(true)
+ .long("config"))
+ .get_matches_from_safe(vec![
+ "prog", "--config=file.conf"
+ ]);
+ assert!(res.is_ok());
+}
+
+#[test]
+fn stdin_char() {
+ let r = App::new("opts")
+ .arg(Arg::from_usage("-f [flag] 'some flag'"))
+ .get_matches_from_safe(vec!["", "-f", "-"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("f"));
+ assert_eq!(m.value_of("f").unwrap(), "-");
+}
+
+#[test]
+fn opts_using_short() {
+ let r = App::new("opts")
+ .args(&[Arg::from_usage("-f [flag] 'some flag'"),
+ Arg::from_usage("-c [color] 'some other flag'")])
+ .get_matches_from_safe(vec!["", "-f", "some", "-c", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("f"));
+ assert_eq!(m.value_of("f").unwrap(), "some");
+ assert!(m.is_present("c"));
+ assert_eq!(m.value_of("c").unwrap(), "other");
+}
+
+#[test]
+fn lots_o_vals() {
+ let r = App::new("opts")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'"))
+ .get_matches_from_safe(vec!["", "-o", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>().len(), 297); // i.e. more than u8
+}
+
+#[test]
+fn opts_using_long_space() {
+ let r = App::new("opts")
+ .args(&[Arg::from_usage("--flag [flag] 'some flag'"),
+ Arg::from_usage("--color [color] 'some other flag'")])
+ .get_matches_from_safe(vec!["", "--flag", "some", "--color", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("flag").unwrap(), "some");
+ assert!(m.is_present("color"));
+ assert_eq!(m.value_of("color").unwrap(), "other");
+}
+
+#[test]
+fn opts_using_long_equals() {
+ let r = App::new("opts")
+ .args(&[Arg::from_usage("--flag [flag] 'some flag'"),
+ Arg::from_usage("--color [color] 'some other flag'")])
+ .get_matches_from_safe(vec!["", "--flag=some", "--color=other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("flag").unwrap(), "some");
+ assert!(m.is_present("color"));
+ assert_eq!(m.value_of("color").unwrap(), "other");
+}
+
+#[test]
+fn opts_using_mixed() {
+ let r = App::new("opts")
+ .args(&[Arg::from_usage("-f, --flag [flag] 'some flag'"),
+ Arg::from_usage("-c, --color [color] 'some other flag'")])
+ .get_matches_from_safe(vec!["", "-f", "some", "--color", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("flag").unwrap(), "some");
+ assert!(m.is_present("color"));
+ assert_eq!(m.value_of("color").unwrap(), "other");
+}
+
+#[test]
+fn opts_using_mixed2() {
+ let r = App::new("opts")
+ .args(&[Arg::from_usage("-f, --flag [flag] 'some flag'"),
+ Arg::from_usage("-c, --color [color] 'some other flag'")])
+ .get_matches_from_safe(vec!["", "--flag=some", "-c", "other"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("flag").unwrap(), "some");
+ assert!(m.is_present("color"));
+ assert_eq!(m.value_of("color").unwrap(), "other");
+}
+
+#[test]
+fn default_values_user_value() {
+ let r = App::new("df")
+ .arg(Arg::from_usage("-o [opt] 'some opt'").default_value("default"))
+ .get_matches_from_safe(vec!["", "-o", "value"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.value_of("o").unwrap(), "value");
+}
+
+#[test]
+fn multiple_vals_pos_arg_equals() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'"))
+ .arg(Arg::from_usage("[file] 'some file'"))
+ .get_matches_from_safe(vec!["", "-o=1", "some"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.value_of("o").unwrap(), "1");
+ assert!(m.is_present("file"));
+ assert_eq!(m.value_of("file").unwrap(), "some");
+}
+
+#[test]
+fn multiple_vals_pos_arg_delim() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'"))
+ .arg(Arg::from_usage("[file] 'some file'"))
+ .get_matches_from_safe(vec!["", "-o", "1,2", "some"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["1", "2"]);
+ assert!(m.is_present("file"));
+ assert_eq!(m.value_of("file").unwrap(), "some");
+}
+
+#[test]
+fn require_delims_no_delim() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'").require_delimiter(true))
+ .arg(Arg::from_usage("[file] 'some file'"))
+ .get_matches_from_safe(vec!["mvae", "-o", "1", "2", "some"]);
+ assert!(r.is_err());
+ let err = r.unwrap_err();
+ assert_eq!(err.kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn require_delims() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'").require_delimiter(true))
+ .arg(Arg::from_usage("[file] 'some file'"))
+ .get_matches_from_safe(vec!["", "-o", "1,2", "some"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["1", "2"]);
+ assert!(m.is_present("file"));
+ assert_eq!(m.value_of("file").unwrap(), "some");
+}
+
+#[test]
+fn leading_hyphen_pass() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'").allow_hyphen_values(true))
+ .get_matches_from_safe(vec!["", "-o", "-2", "3"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2", "3"]);
+}
+
+#[test]
+fn leading_hyphen_fail() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt] 'some opt'"))
+ .get_matches_from_safe(vec!["", "-o", "-2"]);
+ assert!(r.is_err());
+ let m = r.unwrap_err();
+ assert_eq!(m.kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn leading_hyphen_with_flag_after() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'").allow_hyphen_values(true))
+ .arg_from_usage("-f 'some flag'")
+ .get_matches_from_safe(vec!["", "-o", "-2", "-f"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2", "-f"]);
+ assert!(!m.is_present("f"));
+}
+
+#[test]
+fn leading_hyphen_with_flag_before() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'").allow_hyphen_values(true))
+ .arg_from_usage("-f 'some flag'")
+ .get_matches_from_safe(vec!["", "-f", "-o", "-2"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2"]);
+ assert!(m.is_present("f"));
+}
+
+#[test]
+fn leading_hyphen_with_only_pos_follows() {
+ let r = App::new("mvae")
+ .arg(Arg::from_usage("-o [opt]... 'some opt'").number_of_values(1).allow_hyphen_values(true))
+ .arg_from_usage("[arg] 'some arg'")
+ .get_matches_from_safe(vec!["", "-o", "-2", "--", "val"]);
+ assert!(r.is_ok(), "{:?}", r);
+ let m = r.unwrap();
+ assert!(m.is_present("o"));
+ assert_eq!(m.values_of("o").unwrap().collect::<Vec<_>>(), &["-2"]);
+ assert_eq!(m.value_of("arg"), Some("val"));
+}
+
+#[test]
+#[cfg(feature="suggestions")]
+fn did_you_mean() {
+ assert!(test::compare_output(test::complex_app(),
+ "clap-test --optio=foo",
+ DYM,
+ true));
+}
+
+#[test]
+fn issue_665() {
+ let res = App::new("tester")
+ .arg_from_usage("-v, --reroll-count=[N] 'Mark the patch series as PATCH vN'")
+ .arg(Arg::from_usage(
+"--subject-prefix [Subject-Prefix] 'Use [Subject-Prefix] instead of the standard [PATCH] prefix'")
+ .empty_values(false))
+ .get_matches_from_safe(vec!["test", "--subject-prefix", "-v", "2"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue);
+}
+
+#[test]
+fn issue_1047_min_zero_vals_default_val() {
+ let m = App::new("foo")
+ .arg(
+ Arg::with_name("del")
+ .short("d")
+ .long("del")
+ .takes_value(true)
+ .require_equals(true)
+ .min_values(0)
+ .default_value("default"),
+ )
+ .get_matches_from(vec!["foo", "-d"]);
+ assert_eq!(m.occurrences_of("del"), 1);
+ assert_eq!(m.value_of("del"), Some("default"));
+}
+
+fn issue_1105_setup(argv: Vec<&'static str>) -> Result<ArgMatches<'static>, clap::Error> {
+ App::new("opts")
+ .arg_from_usage("-o, --option [opt] 'some option'")
+ .arg_from_usage("--flag 'some flag'")
+ .get_matches_from_safe(argv)
+}
+
+#[test]
+fn issue_1105_empty_value_long_fail() {
+ let r = issue_1105_setup(vec!["app", "--option", "--flag"]);
+ assert!(r.is_err());
+ assert_eq!(r.unwrap_err().kind, ErrorKind::EmptyValue);
+}
+
+#[test]
+fn issue_1105_empty_value_long_explicit() {
+ let r = issue_1105_setup(vec!["app", "--option", ""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert_eq!(m.value_of("option"), Some(""));
+}
+
+#[test]
+fn issue_1105_empty_value_long_equals() {
+ let r = issue_1105_setup(vec!["app", "--option="]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert_eq!(m.value_of("option"), Some(""));
+}
+
+#[test]
+fn issue_1105_empty_value_short_fail() {
+ let r = issue_1105_setup(vec!["app", "-o", "--flag"]);
+ assert!(r.is_err());
+ assert_eq!(r.unwrap_err().kind, ErrorKind::EmptyValue);
+}
+
+#[test]
+fn issue_1105_empty_value_short_explicit() {
+ let r = issue_1105_setup(vec!["app", "-o", ""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert_eq!(m.value_of("option"), Some(""));
+}
+
+#[test]
+fn issue_1105_empty_value_short_equals() {
+ let r = issue_1105_setup(vec!["app", "-o="]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert_eq!(m.value_of("option"), Some(""));
+}
+
+#[test]
+fn issue_1105_empty_value_short_explicit_no_space() {
+ let r = issue_1105_setup(vec!["app", "-o", ""]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert_eq!(m.value_of("option"), Some(""));
+}
diff --git a/clap/tests/positionals.rs b/clap/tests/positionals.rs
new file mode 100644
index 0000000..bf0f79f
--- /dev/null
+++ b/clap/tests/positionals.rs
@@ -0,0 +1,274 @@
+extern crate clap;
+
+use clap::{App, Arg, ErrorKind};
+
+#[test]
+fn only_pos_follow() {
+ let r = App::new("onlypos")
+ .args(&[Arg::from_usage("-f [flag] 'some opt'"),
+ Arg::from_usage("[arg] 'some arg'")])
+ .get_matches_from_safe(vec!["", "--", "-f"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert!(!m.is_present("f"));
+ assert_eq!(m.value_of("arg").unwrap(), "-f");
+}
+
+#[test]
+fn issue_946() {
+ let r = App::new("compiletest")
+ .setting(clap::AppSettings::AllowLeadingHyphen)
+ .args_from_usage("--exact 'filters match exactly'")
+ .arg(clap::Arg::with_name("filter")
+ .index(1)
+ .takes_value(true)
+ .help("filters to apply to output"))
+ .get_matches_from_safe(vec!["compiletest", "--exact"]);
+ assert!(r.is_ok(), "{:#?}", r);
+ let matches = r.unwrap();
+
+ assert!(matches.is_present("exact"));
+ assert!(matches.value_of("filter").is_none());
+}
+
+#[test]
+fn positional() {
+ let r = App::new("positional")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::with_name("positional")
+ .index(1)
+ ])
+ .get_matches_from_safe(vec!["", "-f", "test"]);
+ assert!(r.is_ok(), "{:#?}", r);
+ let m = r.unwrap();
+ assert!(m.is_present("positional"));
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("positional").unwrap(), "test");
+
+ let m = App::new("positional")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::with_name("positional")
+ .index(1)
+ ])
+ .get_matches_from(vec!["", "test", "--flag"]);
+ assert!(m.is_present("positional"));
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("positional").unwrap(), "test");
+}
+
+#[test]
+fn lots_o_vals() {
+ let r = App::new("opts")
+ .arg(
+ Arg::from_usage("[opt]... 'some pos'"),
+ )
+ .get_matches_from_safe(vec!["",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
+ ]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>().len(), 297); // i.e. more than u8
+}
+
+#[test]
+fn positional_multiple() {
+ let r = App::new("positional_multiple")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::with_name("positional")
+ .index(1)
+ .multiple(true)
+ ])
+ .get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]);
+ assert!(r.is_ok(), "{:#?}", r);
+ let m = r.unwrap();
+ assert!(m.is_present("positional"));
+ assert!(m.is_present("flag"));
+ assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test1", "test2", "test3"]);
+}
+
+#[test]
+fn positional_multiple_3() {
+ let r = App::new("positional_multiple")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::with_name("positional")
+ .index(1)
+ .multiple(true)
+ ])
+ .get_matches_from_safe(vec!["", "test1", "test2", "test3", "--flag"]);
+ assert!(r.is_ok(), "{:#?}", r);
+ let m = r.unwrap();
+ assert!(m.is_present("positional"));
+ assert!(m.is_present("flag"));
+ assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test1", "test2", "test3"]);
+}
+
+#[test]
+fn positional_multiple_2() {
+ let result = App::new("positional_multiple")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::with_name("positional")
+ .index(1)
+ ])
+ .get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn positional_possible_values() {
+ let r = App::new("positional_possible_values")
+ .args(&[
+ Arg::from_usage("-f, --flag 'some flag'"),
+ Arg::with_name("positional")
+ .index(1)
+ .possible_value("test123")
+ ])
+ .get_matches_from_safe(vec!["", "-f", "test123"]);
+ assert!(r.is_ok(), "{:#?}", r);
+ let m = r.unwrap();
+ assert!(m.is_present("positional"));
+ assert!(m.is_present("flag"));
+ assert_eq!(&*m.values_of("positional").unwrap().collect::<Vec<_>>(), &["test123"]);
+}
+
+#[test]
+fn create_positional() {
+ let _ = App::new("test")
+ .arg(Arg::with_name("test")
+ .index(1)
+ .help("testing testing"))
+ .get_matches_from(vec![""]);
+}
+
+#[test]
+fn positional_hyphen_does_not_panic() {
+ let _ = App::new("test")
+ .arg(Arg::with_name("dummy"))
+ .get_matches_from(vec!["test", "-"]);
+}
+
+#[test]
+fn single_positional_usage_string() {
+ let m = App::new("test").arg_from_usage("[FILE] 'some file'").get_matches_from(vec!["test"]);
+ assert_eq!(m.usage(), "USAGE:\n test [FILE]");
+}
+
+#[test]
+fn single_positional_multiple_usage_string() {
+ let m = App::new("test").arg_from_usage("[FILE]... 'some file'").get_matches_from(vec!["test"]);
+ assert_eq!(m.usage(), "USAGE:\n test [FILE]...");
+}
+
+#[test]
+fn multiple_positional_usage_string() {
+ let m = App::new("test")
+ .arg_from_usage("[FILE] 'some file'")
+ .arg_from_usage("[FILES]... 'some file'")
+ .get_matches_from(vec!["test"]);
+ assert_eq!(m.usage(), "USAGE:\n test [ARGS]");
+}
+
+#[test]
+fn multiple_positional_one_required_usage_string() {
+ let m = App::new("test")
+ .arg_from_usage("<FILE> 'some file'")
+ .arg_from_usage("[FILES]... 'some file'")
+ .get_matches_from(vec!["test", "file"]);
+ assert_eq!(m.usage(), "USAGE:\n test <FILE> [FILES]...");
+}
+
+#[test]
+fn single_positional_required_usage_string() {
+ let m = App::new("test")
+ .arg_from_usage("<FILE> 'some file'")
+ .get_matches_from(vec!["test", "file"]);
+ assert_eq!(m.usage(), "USAGE:\n test <FILE>");
+}
+
+#[test]
+#[should_panic]
+fn missing_required() {
+ let r = App::new("test")
+ .arg_from_usage("[FILE1] 'some file'")
+ .arg_from_usage("<FILE2> 'some file'")
+ .get_matches_from_safe(vec!["test", "file"]);
+ assert!(r.is_err());
+ assert_eq!(r.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn missing_required_2() {
+ let r = App::new("test")
+ .arg_from_usage("<FILE1> 'some file'")
+ .arg_from_usage("<FILE2> 'some file'")
+ .get_matches_from_safe(vec!["test", "file"]);
+ assert!(r.is_err());
+ assert_eq!(r.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn last_positional() {
+ let r = App::new("test")
+ .arg_from_usage("<TARGET> 'some target'")
+ .arg_from_usage("[CORPUS] 'some corpus'")
+ .arg(Arg::from_usage("[ARGS]... 'some file'").last(true))
+ .get_matches_from_safe(vec!["test", "tgt", "--", "arg"]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert_eq!(m.values_of("ARGS").unwrap().collect::<Vec<_>>(), &["arg"]);
+}
+
+#[test]
+fn last_positional_no_double_dash() {
+ let r = App::new("test")
+ .arg_from_usage("<TARGET> 'some target'")
+ .arg_from_usage("[CORPUS] 'some corpus'")
+ .arg(Arg::from_usage("[ARGS]... 'some file'").last(true))
+ .get_matches_from_safe(vec!["test", "tgt", "crp", "arg"]);
+ assert!(r.is_err());
+ assert_eq!(r.unwrap_err().kind, ErrorKind::UnknownArgument);
+}
+
+#[test]
+fn last_positional_second_to_last_mult() {
+ let r = App::new("test")
+ .arg_from_usage("<TARGET> 'some target'")
+ .arg_from_usage("[CORPUS]... 'some corpus'")
+ .arg(Arg::from_usage("[ARGS]... 'some file'").last(true))
+ .get_matches_from_safe(vec!["test", "tgt", "crp1", "crp2", "--", "arg"]);
+ assert!(r.is_ok(), "{:?}", r.unwrap_err().kind);
+}
diff --git a/clap/tests/posix_compatible.rs b/clap/tests/posix_compatible.rs
new file mode 100644
index 0000000..26d9f71
--- /dev/null
+++ b/clap/tests/posix_compatible.rs
@@ -0,0 +1,292 @@
+extern crate clap;
+
+use clap::{App, Arg, ErrorKind};
+
+#[test]
+fn flag_overrides_itself() {
+ let res = App::new("posix")
+ .arg(Arg::from_usage("--flag 'some flag'").overrides_with("flag"))
+ .get_matches_from_safe(vec!["", "--flag", "--flag"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("flag"));
+ assert_eq!(m.occurrences_of("flag"), 1);
+}
+
+#[test]
+fn mult_flag_overrides_itself() {
+ let res = App::new("posix")
+ .arg(Arg::from_usage("--flag... 'some flag'").overrides_with("flag"))
+ .get_matches_from_safe(vec!["", "--flag", "--flag", "--flag", "--flag"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("flag"));
+ assert_eq!(m.occurrences_of("flag"), 4);
+}
+
+#[test]
+fn option_overrides_itself() {
+ let res = App::new("posix")
+ .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("opt"))
+ .get_matches_from_safe(vec!["", "--opt=some", "--opt=other"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.occurrences_of("opt"), 1);
+ assert_eq!(m.value_of("opt"), Some("other"));
+}
+
+#[test]
+fn mult_option_require_delim_overrides_itself() {
+ let res = App::new("posix")
+ .arg(Arg::from_usage("--opt [val]... 'some option'")
+ .overrides_with("opt")
+ .number_of_values(1)
+ .require_delimiter(true))
+ .get_matches_from_safe(vec!["", "--opt=some", "--opt=other", "--opt=one,two"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.occurrences_of("opt"), 3);
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["some", "other", "one", "two"]);
+}
+
+#[test]
+fn mult_option_overrides_itself() {
+ let res = App::new("posix")
+ .arg(Arg::from_usage("--opt [val]... 'some option'")
+ .overrides_with("opt"))
+ .get_matches_from_safe(vec!["", "--opt", "first", "overides", "--opt", "some", "other", "val"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("opt"));
+ assert_eq!(m.occurrences_of("opt"), 2);
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["first", "overides", "some", "other", "val"]);
+}
+
+#[test]
+fn option_use_delim_false_override_itself() {
+
+ let m = App::new("posix")
+ .arg(Arg::from_usage("--opt [val] 'some option'")
+ .overrides_with("opt")
+ .use_delimiter(false))
+ .get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]);
+ assert!(m.is_present("opt"));
+ assert_eq!(m.occurrences_of("opt"), 1);
+ assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["one,two"]);
+}
+
+#[test]
+fn pos_mult_overrides_itself() {
+ // opts with multiple
+ let res = App::new("posix")
+ .arg(Arg::from_usage("[val]... 'some pos'").overrides_with("val"))
+ .get_matches_from_safe(vec!["", "some", "other", "value"]);
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("val"));
+ assert_eq!(m.occurrences_of("val"), 3);
+ assert_eq!(m.values_of("val").unwrap().collect::<Vec<_>>(), &["some", "other", "value"]);
+}
+
+#[test]
+fn posix_compatible_flags_long() {
+ let m = App::new("posix")
+ .arg(Arg::from_usage("--flag 'some flag'").overrides_with("color"))
+ .arg(Arg::from_usage("--color 'some other flag'"))
+ .get_matches_from(vec!["", "--flag", "--color"]);
+ assert!(m.is_present("color"));
+ assert!(!m.is_present("flag"));
+
+ let m = App::new("posix")
+ .arg(Arg::from_usage("--flag 'some flag'").overrides_with("color"))
+ .arg(Arg::from_usage("--color 'some other flag'"))
+ .get_matches_from(vec!["", "--color", "--flag"]);
+ assert!(!m.is_present("color"));
+ assert!(m.is_present("flag"));
+}
+
+#[test]
+fn posix_compatible_flags_short() {
+ let m = App::new("posix")
+ .arg(Arg::from_usage("-f, --flag 'some flag'").overrides_with("color"))
+ .arg(Arg::from_usage("-c, --color 'some other flag'"))
+ .get_matches_from(vec!["", "-f", "-c"]);
+ assert!(m.is_present("color"));
+ assert!(!m.is_present("flag"));
+
+ let m = App::new("posix")
+ .arg(Arg::from_usage("-f, --flag 'some flag'").overrides_with("color"))
+ .arg(Arg::from_usage("-c, --color 'some other flag'"))
+ .get_matches_from(vec!["", "-c", "-f"]);
+ assert!(!m.is_present("color"));
+ assert!(m.is_present("flag"));
+}
+
+#[test]
+fn posix_compatible_opts_long() {
+ let m = App::new("posix")
+ .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
+ .arg(Arg::from_usage("--color [color] 'some other flag'"))
+ .get_matches_from(vec!["", "--flag", "some" ,"--color", "other"]);
+ assert!(m.is_present("color"));
+ assert_eq!(m.value_of("color").unwrap(), "other");
+ assert!(!m.is_present("flag"));
+
+ let m = App::new("posix")
+ .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
+ .arg(Arg::from_usage("--color [color] 'some other flag'"))
+ .get_matches_from(vec!["", "--color", "some" ,"--flag", "other"]);
+ assert!(!m.is_present("color"));
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("flag").unwrap(), "other");
+}
+
+#[test]
+fn posix_compatible_opts_long_equals() {
+ let m = App::new("posix")
+ .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
+ .arg(Arg::from_usage("--color [color] 'some other flag'"))
+ .get_matches_from(vec!["", "--flag=some" ,"--color=other"]);
+ assert!(m.is_present("color"));
+ assert_eq!(m.value_of("color").unwrap(), "other");
+ assert!(!m.is_present("flag"));
+
+ let m = App::new("posix")
+ .arg(Arg::from_usage("--flag [flag] 'some flag'").overrides_with("color"))
+ .arg(Arg::from_usage("--color [color] 'some other flag'"))
+ .get_matches_from(vec!["", "--color=some" ,"--flag=other"]);
+ assert!(!m.is_present("color"));
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("flag").unwrap(), "other");
+}
+
+#[test]
+fn posix_compatible_opts_short() {
+ let m = App::new("posix")
+ .arg(Arg::from_usage("-f [flag] 'some flag'").overrides_with("c"))
+ .arg(Arg::from_usage("-c [color] 'some other flag'"))
+ .get_matches_from(vec!["", "-f", "some", "-c", "other"]);
+ assert!(m.is_present("c"));
+ assert_eq!(m.value_of("c").unwrap(), "other");
+ assert!(!m.is_present("f"));
+
+ let m = App::new("posix")
+ .arg(Arg::from_usage("-f [flag] 'some flag'").overrides_with("c"))
+ .arg(Arg::from_usage("-c [color] 'some other flag'"))
+ .get_matches_from(vec!["", "-c", "some", "-f", "other"]);
+ assert!(!m.is_present("c"));
+ assert!(m.is_present("f"));
+ assert_eq!(m.value_of("f").unwrap(), "other");
+}
+
+#[test]
+fn conflict_overriden() {
+ let m = App::new("conflict_overriden")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("debug"))
+ .arg(Arg::from_usage("-d, --debug 'other flag'"))
+ .arg(Arg::from_usage("-c, --color 'third flag'")
+ .overrides_with("flag"))
+ .get_matches_from(vec!["", "-f", "-c", "-d"]);
+ assert!(m.is_present("color"));
+ assert!(!m.is_present("flag"));
+ assert!(m.is_present("debug"));
+}
+
+#[test]
+fn conflict_overriden_2() {
+ let result = App::new("conflict_overriden")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("debug"))
+ .arg(Arg::from_usage("-d, --debug 'other flag'"))
+ .arg(Arg::from_usage("-c, --color 'third flag'")
+ .overrides_with("flag"))
+ .get_matches_from_safe(vec!["", "-f", "-d", "-c"]);
+ assert!(result.is_ok());
+ let m = result.unwrap();
+ assert!(m.is_present("color"));
+ assert!(m.is_present("debug"));
+ assert!(!m.is_present("flag"));
+}
+
+#[test]
+fn conflict_overriden_3() {
+ let result = App::new("conflict_overriden")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("debug"))
+ .arg(Arg::from_usage("-d, --debug 'other flag'"))
+ .arg(Arg::from_usage("-c, --color 'third flag'")
+ .overrides_with("flag"))
+ .get_matches_from_safe(vec!["", "-d", "-c", "-f"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::ArgumentConflict);
+}
+
+#[test]
+fn conflict_overriden_4() {
+ let m = App::new("conflict_overriden")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .conflicts_with("debug"))
+ .arg(Arg::from_usage("-d, --debug 'other flag'"))
+ .arg(Arg::from_usage("-c, --color 'third flag'")
+ .overrides_with("flag"))
+ .get_matches_from(vec!["", "-d", "-f", "-c"]);
+ assert!(m.is_present("color"));
+ assert!(!m.is_present("flag"));
+ assert!(m.is_present("debug"));
+}
+
+#[test]
+fn pos_required_overridden_by_flag() {
+ let result = App::new("require_overriden")
+ .arg(Arg::with_name("pos")
+ .index(1)
+ .required(true))
+ .arg(Arg::from_usage("-c, --color 'some flag'")
+ .overrides_with("pos"))
+ .get_matches_from_safe(vec!["", "test", "-c"]);
+ assert!(result.is_ok(), "{:?}", result.unwrap_err());
+}
+
+#[test]
+fn require_overriden_2() {
+ let m = App::new("require_overriden")
+ .arg(Arg::with_name("req_pos")
+ .required(true))
+ .arg(Arg::from_usage("-c, --color 'other flag'")
+ .overrides_with("req_pos"))
+ .get_matches_from(vec!["", "-c", "req_pos"]);
+ assert!(!m.is_present("color"));
+ assert!(m.is_present("req_pos"));
+}
+
+#[test]
+fn require_overriden_3() {
+ let m = App::new("require_overriden")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .requires("debug"))
+ .arg(Arg::from_usage("-d, --debug 'other flag'"))
+ .arg(Arg::from_usage("-c, --color 'third flag'")
+ .overrides_with("flag"))
+ .get_matches_from(vec!["", "-f", "-c"]);
+ assert!(m.is_present("color"));
+ assert!(!m.is_present("flag"));
+ assert!(!m.is_present("debug"));
+}
+
+#[test]
+fn require_overriden_4() {
+ let result = App::new("require_overriden")
+ .arg(Arg::from_usage("-f, --flag 'some flag'")
+ .requires("debug"))
+ .arg(Arg::from_usage("-d, --debug 'other flag'"))
+ .arg(Arg::from_usage("-c, --color 'third flag'")
+ .overrides_with("flag"))
+ .get_matches_from_safe(vec!["", "-c", "-f"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
diff --git a/clap/tests/possible_values.rs b/clap/tests/possible_values.rs
new file mode 100644
index 0000000..80772bd
--- /dev/null
+++ b/clap/tests/possible_values.rs
@@ -0,0 +1,266 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+#[allow(deprecated, unused_imports)]
+use std::ascii::AsciiExt;
+
+use clap::{App, Arg, ErrorKind};
+
+#[cfg(feature = "suggestions")]
+static PV_ERROR: &'static str = "error: 'slo' isn't a valid value for '--Option <option3>'
+\t[possible values: fast, slow]
+
+\tDid you mean 'slow'?
+
+USAGE:
+ clap-test --Option <option3>
+
+For more information try --help";
+
+#[cfg(not(feature = "suggestions"))]
+static PV_ERROR: &'static str = "error: 'slo' isn't a valid value for '--Option <option3>'
+\t[possible values: fast, slow]
+
+
+USAGE:
+ clap-test --Option <option3>
+
+For more information try --help";
+
+#[test]
+fn possible_values_of_positional() {
+ let m = App::new("possible_values")
+ .arg(
+ Arg::with_name("positional")
+ .index(1)
+ .possible_value("test123"),
+ )
+ .get_matches_from_safe(vec!["myprog", "test123"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("positional"));
+ assert_eq!(m.value_of("positional"), Some("test123"));
+}
+
+#[test]
+fn possible_values_of_positional_fail() {
+ let m = App::new("possible_values")
+ .arg(
+ Arg::with_name("positional")
+ .index(1)
+ .possible_value("test123"),
+ )
+ .get_matches_from_safe(vec!["myprog", "notest"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
+}
+
+#[test]
+fn possible_values_of_positional_multiple() {
+ let m = App::new("possible_values")
+ .arg(
+ Arg::with_name("positional")
+ .index(1)
+ .possible_value("test123")
+ .possible_value("test321")
+ .multiple(true),
+ )
+ .get_matches_from_safe(vec!["myprog", "test123", "test321"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("positional"));
+ assert_eq!(
+ m.values_of("positional").unwrap().collect::<Vec<_>>(),
+ vec!["test123", "test321"]
+ );
+}
+
+#[test]
+fn possible_values_of_positional_multiple_fail() {
+ let m = App::new("possible_values")
+ .arg(
+ Arg::with_name("positional")
+ .index(1)
+ .possible_value("test123")
+ .possible_value("test321")
+ .multiple(true),
+ )
+ .get_matches_from_safe(vec!["myprog", "test123", "notest"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
+}
+
+#[test]
+fn possible_values_of_option() {
+ let m = App::new("possible_values")
+ .arg(
+ Arg::with_name("option")
+ .short("-o")
+ .long("--option")
+ .takes_value(true)
+ .possible_value("test123"),
+ )
+ .get_matches_from_safe(vec!["myprog", "--option", "test123"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(m.value_of("option"), Some("test123"));
+}
+
+#[test]
+fn possible_values_of_option_fail() {
+ let m = App::new("possible_values")
+ .arg(
+ Arg::with_name("option")
+ .short("-o")
+ .long("--option")
+ .takes_value(true)
+ .possible_value("test123"),
+ )
+ .get_matches_from_safe(vec!["myprog", "--option", "notest"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
+}
+
+#[test]
+fn possible_values_of_option_multiple() {
+ let m = App::new("possible_values")
+ .arg(
+ Arg::with_name("option")
+ .short("-o")
+ .long("--option")
+ .takes_value(true)
+ .possible_value("test123")
+ .possible_value("test321")
+ .multiple(true),
+ )
+ .get_matches_from_safe(vec!["", "--option", "test123", "--option", "test321"]);
+
+ assert!(m.is_ok());
+ let m = m.unwrap();
+
+ assert!(m.is_present("option"));
+ assert_eq!(
+ m.values_of("option").unwrap().collect::<Vec<_>>(),
+ vec!["test123", "test321"]
+ );
+}
+
+#[test]
+fn possible_values_of_option_multiple_fail() {
+ let m = App::new("possible_values")
+ .arg(
+ Arg::with_name("option")
+ .short("-o")
+ .long("--option")
+ .takes_value(true)
+ .possible_value("test123")
+ .possible_value("test321")
+ .multiple(true),
+ )
+ .get_matches_from_safe(vec!["", "--option", "test123", "--option", "notest"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
+}
+
+#[test]
+fn possible_values_output() {
+ assert!(test::compare_output(
+ test::complex_app(),
+ "clap-test -O slo",
+ PV_ERROR,
+ true
+ ));
+}
+
+#[test]
+fn case_insensitive() {
+ let m = App::new("pv")
+ .arg(
+ Arg::with_name("option")
+ .short("-o")
+ .long("--option")
+ .takes_value(true)
+ .possible_value("test123")
+ .possible_value("test321")
+ .case_insensitive(true),
+ )
+ .get_matches_from_safe(vec!["pv", "--option", "TeSt123"]);
+
+ assert!(m.is_ok());
+ assert!(
+ m.unwrap()
+ .value_of("option")
+ .unwrap()
+ .eq_ignore_ascii_case("test123")
+ );
+}
+
+#[test]
+fn case_insensitive_faili() {
+ let m = App::new("pv")
+ .arg(
+ Arg::with_name("option")
+ .short("-o")
+ .long("--option")
+ .takes_value(true)
+ .possible_value("test123")
+ .possible_value("test321"),
+ )
+ .get_matches_from_safe(vec!["pv", "--option", "TeSt123"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
+}
+
+#[test]
+fn case_insensitive_multiple() {
+ let m = App::new("pv")
+ .arg(
+ Arg::with_name("option")
+ .short("-o")
+ .long("--option")
+ .takes_value(true)
+ .possible_value("test123")
+ .possible_value("test321")
+ .multiple(true)
+ .case_insensitive(true),
+ )
+ .get_matches_from_safe(vec!["pv", "--option", "TeSt123", "teST123", "tESt321"]);
+
+ assert!(m.is_ok());
+ assert_eq!(
+ m.unwrap().values_of("option").unwrap().collect::<Vec<_>>(),
+ &["TeSt123", "teST123", "tESt321"]
+ );
+}
+
+#[test]
+fn case_insensitive_multiple_fail() {
+ let m = App::new("pv")
+ .arg(
+ Arg::with_name("option")
+ .short("-o")
+ .long("--option")
+ .takes_value(true)
+ .possible_value("test123")
+ .possible_value("test321")
+ .multiple(true),
+ )
+ .get_matches_from_safe(vec!["pv", "--option", "test123", "teST123", "test321"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
+}
diff --git a/clap/tests/propagate_globals.rs b/clap/tests/propagate_globals.rs
new file mode 100644
index 0000000..ee77ce0
--- /dev/null
+++ b/clap/tests/propagate_globals.rs
@@ -0,0 +1,148 @@
+extern crate clap;
+extern crate regex;
+
+#[cfg(test)]
+mod tests {
+ include!("../clap-test.rs");
+ use clap::{App, Arg, SubCommand, ArgMatches};
+
+ fn get_app() -> App<'static, 'static> {
+ App::new("myprog")
+ .arg(Arg::with_name("GLOBAL_ARG")
+ .long("global-arg")
+ .help(
+ "Specifies something needed by the subcommands",
+ )
+ .global(true)
+ .takes_value(true)
+ .default_value("default_value"))
+ .arg(Arg::with_name("GLOBAL_FLAG")
+ .long("global-flag")
+ .help(
+ "Specifies something needed by the subcommands",
+ )
+ .multiple(true)
+ .global(true))
+ .subcommand(SubCommand::with_name("outer")
+ .subcommand(SubCommand::with_name("inner")))
+ }
+
+ fn get_matches(app: App<'static, 'static>, argv: &'static str) -> ArgMatches<'static> {
+ app.get_matches_from(argv.split(' ').collect::<Vec<_>>())
+ }
+
+ fn get_outer_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> {
+ m.subcommand_matches("outer").expect("could not access outer subcommand")
+ }
+
+ fn get_inner_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> {
+ get_outer_matches(m).subcommand_matches("inner").expect("could not access inner subcommand")
+ }
+
+ fn top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool {
+ m.value_of("GLOBAL_ARG") == val.into()
+ }
+
+ fn inner_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool {
+ get_inner_matches(m).value_of("GLOBAL_ARG") == val.into()
+ }
+
+ fn outer_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool {
+ get_outer_matches(m).value_of("GLOBAL_ARG") == val.into()
+ }
+
+ fn top_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool {
+ (m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
+ }
+
+ fn inner_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool {
+ let m = get_inner_matches(m);
+ (m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
+ }
+
+ fn outer_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool {
+ let m = get_outer_matches(m);
+ (m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
+ }
+
+ #[test]
+ fn global_arg_used_top_level() {
+ let m = get_matches(get_app(), "myprog --global-arg=some_value outer inner");
+
+ assert!(top_can_access_arg(&m, "some_value"));
+ assert!(inner_can_access_arg(&m, "some_value"));
+ assert!(outer_can_access_arg(&m, "some_value"));
+ }
+
+ #[test]
+ fn global_arg_used_outer() {
+ let m = get_matches(get_app(), "myprog outer --global-arg=some_value inner");
+
+ assert!(top_can_access_arg(&m, "some_value"));
+ assert!(inner_can_access_arg(&m, "some_value"));
+ assert!(outer_can_access_arg(&m, "some_value"));
+ }
+
+ #[test]
+ fn global_arg_used_inner() {
+ let m = get_matches(get_app(), "myprog outer inner --global-arg=some_value");
+
+ assert!(top_can_access_arg(&m, "some_value"));
+ assert!(inner_can_access_arg(&m, "some_value"));
+ assert!(outer_can_access_arg(&m, "some_value"));
+ }
+
+ #[test]
+ fn global_arg_default_value() {
+ let m = get_matches(get_app(), "myprog outer inner");
+
+ assert!(top_can_access_arg(&m, "default_value"));
+ assert!(inner_can_access_arg(&m, "default_value"));
+ assert!(outer_can_access_arg(&m, "default_value"));
+ }
+
+ #[test]
+ fn global_flag_used_top_level() {
+ let m = get_matches(get_app(), "myprog --global-flag outer inner");
+
+ assert!(top_can_access_flag(&m, true, 1));
+ assert!(inner_can_access_flag(&m, true, 1));
+ assert!(outer_can_access_flag(&m, true, 1));
+ }
+
+ #[test]
+ fn global_flag_used_outer() {
+ let m = get_matches(get_app(), "myprog outer --global-flag inner");
+
+ assert!(top_can_access_flag(&m, true, 1));
+ assert!(inner_can_access_flag(&m, true, 1));
+ assert!(outer_can_access_flag(&m, true, 1));
+ }
+
+ #[test]
+ fn global_flag_used_inner() {
+ let m = get_matches(get_app(), "myprog outer inner --global-flag");
+
+ assert!(top_can_access_flag(&m, true, 1));
+ assert!(inner_can_access_flag(&m, true, 1));
+ assert!(outer_can_access_flag(&m, true, 1));
+ }
+
+ #[test]
+ fn global_flag_2x_used_top_level() {
+ let m = get_matches(get_app(), "myprog --global-flag --global-flag outer inner");
+
+ assert!(top_can_access_flag(&m, true, 2));
+ assert!(inner_can_access_flag(&m, true, 2));
+ assert!(outer_can_access_flag(&m, true, 2));
+ }
+
+ #[test]
+ fn global_flag_2x_used_inner() {
+ let m = get_matches(get_app(), "myprog outer inner --global-flag --global-flag");
+
+ assert!(top_can_access_flag(&m, true, 2));
+ assert!(inner_can_access_flag(&m, true, 2));
+ assert!(outer_can_access_flag(&m, true, 2));
+ }
+}
diff --git a/clap/tests/require.rs b/clap/tests/require.rs
new file mode 100644
index 0000000..7121aa5
--- /dev/null
+++ b/clap/tests/require.rs
@@ -0,0 +1,688 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, Arg, ErrorKind, ArgGroup};
+
+static REQUIRE_EQUALS: &'static str = "error: The following required arguments were not provided:
+ --opt=<FILE>
+
+USAGE:
+ clap-test --opt=<FILE>
+
+For more information try --help";
+
+static MISSING_REQ: &'static str = "error: The following required arguments were not provided:
+ <positional2>
+ --long-option-2 <option2>
+
+USAGE:
+ clap-test <positional2> -F --long-option-2 <option2>
+
+For more information try --help";
+
+static COND_REQ_IN_USAGE: &'static str = "error: The following required arguments were not provided:
+ --output <output>
+
+USAGE:
+ test --input <input> --output <output> --target <target>
+
+For more information try --help";
+
+static ISSUE_1158: &'static str = "error: The following required arguments were not provided:
+ -x <X>
+ -y <Y>
+ -z <Z>
+
+USAGE:
+ example [OPTIONS] <ID> -x <X> -y <Y> -z <Z>
+
+For more information try --help";
+
+#[test]
+fn issue_1158_conflicting_requirements() {
+ let app = App::new("example")
+ .arg(Arg::from_usage("-c, --config [FILE] 'Custom config file.'")
+ .required_unless("ID")
+ .conflicts_with("ID"))
+ .arg(Arg::from_usage("[ID] 'ID'")
+ .required_unless("config")
+ .conflicts_with("config")
+ .requires_all(&["x", "y", "z"]))
+ .arg(Arg::from_usage("-x [X] 'X'"))
+ .arg(Arg::from_usage("-y [Y] 'Y'"))
+ .arg(Arg::from_usage("-z [Z] 'Z'"));
+
+ assert!(test::compare_output(app, "example id", ISSUE_1158, true));
+}
+
+#[test]
+fn issue_1158_conflicting_requirements_rev() {
+ let res = App::new("example")
+ .arg(Arg::from_usage("-c, --config [FILE] 'Custom config file.'")
+ .required_unless("ID")
+ .conflicts_with("ID"))
+ .arg(Arg::from_usage("[ID] 'ID'")
+ .required_unless("config")
+ .conflicts_with("config")
+ .requires_all(&["x", "y", "z"]))
+ .arg(Arg::from_usage("-x [X] 'X'"))
+ .arg(Arg::from_usage("-y [Y] 'Y'"))
+ .arg(Arg::from_usage("-z [Z] 'Z'"))
+ .get_matches_from_safe(vec!["example", "--config", "some"]);
+
+ assert!(res.is_ok());
+}
+
+#[test]
+fn flag_required() {
+ let result = App::new("flag_required")
+ .arg(Arg::from_usage("-f, --flag 'some flag'").requires("color"))
+ .arg(Arg::from_usage("-c, --color 'third flag'"))
+ .get_matches_from_safe(vec!["", "-f"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn flag_required_2() {
+ let m = App::new("flag_required")
+ .arg(Arg::from_usage("-f, --flag 'some flag'").requires("color"))
+ .arg(Arg::from_usage("-c, --color 'third flag'"))
+ .get_matches_from(vec!["", "-f", "-c"]);
+ assert!(m.is_present("color"));
+ assert!(m.is_present("flag"));
+}
+
+#[test]
+fn option_required() {
+ let result = App::new("option_required")
+ .arg(Arg::from_usage("-f [flag] 'some flag'").requires("c"))
+ .arg(Arg::from_usage("-c [color] 'third flag'"))
+ .get_matches_from_safe(vec!["", "-f", "val"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn option_required_2() {
+ let m = App::new("option_required")
+ .arg(Arg::from_usage("-f [flag] 'some flag'").requires("c"))
+ .arg(Arg::from_usage("-c [color] 'third flag'"))
+ .get_matches_from(vec!["", "-f", "val", "-c", "other_val"]);
+ assert!(m.is_present("c"));
+ assert_eq!(m.value_of("c").unwrap(), "other_val");
+ assert!(m.is_present("f"));
+ assert_eq!(m.value_of("f").unwrap(), "val");
+}
+
+#[test]
+fn positional_required() {
+ let result = App::new("positional_required")
+ .arg(Arg::with_name("flag")
+ .index(1)
+ .required(true))
+ .get_matches_from_safe(vec![""]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn positional_required_2() {
+ let m = App::new("positional_required")
+ .arg(Arg::with_name("flag")
+ .index(1)
+ .required(true))
+ .get_matches_from(vec!["", "someval"]);
+ assert!(m.is_present("flag"));
+ assert_eq!(m.value_of("flag").unwrap(), "someval");
+}
+
+#[test]
+fn group_required() {
+ let result = App::new("group_required")
+ .arg(Arg::from_usage("-f, --flag 'some flag'"))
+ .group(ArgGroup::with_name("gr")
+ .required(true)
+ .arg("some")
+ .arg("other"))
+ .arg(Arg::from_usage("--some 'some arg'"))
+ .arg(Arg::from_usage("--other 'other arg'"))
+ .get_matches_from_safe(vec!["", "-f"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn group_required_2() {
+ let m = App::new("group_required")
+ .arg(Arg::from_usage("-f, --flag 'some flag'"))
+ .group(ArgGroup::with_name("gr")
+ .required(true)
+ .arg("some")
+ .arg("other"))
+ .arg(Arg::from_usage("--some 'some arg'"))
+ .arg(Arg::from_usage("--other 'other arg'"))
+ .get_matches_from(vec!["", "-f", "--some"]);
+ assert!(m.is_present("some"));
+ assert!(!m.is_present("other"));
+ assert!(m.is_present("flag"));
+}
+
+#[test]
+fn group_required_3() {
+ let m = App::new("group_required")
+ .arg(Arg::from_usage("-f, --flag 'some flag'"))
+ .group(ArgGroup::with_name("gr")
+ .required(true)
+ .arg("some")
+ .arg("other"))
+ .arg(Arg::from_usage("--some 'some arg'"))
+ .arg(Arg::from_usage("--other 'other arg'"))
+ .get_matches_from(vec!["", "-f", "--other"]);
+ assert!(!m.is_present("some"));
+ assert!(m.is_present("other"));
+ assert!(m.is_present("flag"));
+}
+
+#[test]
+fn arg_require_group() {
+ let result = App::new("arg_require_group")
+ .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr"))
+ .group(ArgGroup::with_name("gr")
+ .arg("some")
+ .arg("other"))
+ .arg(Arg::from_usage("--some 'some arg'"))
+ .arg(Arg::from_usage("--other 'other arg'"))
+ .get_matches_from_safe(vec!["", "-f"]);
+ assert!(result.is_err());
+ let err = result.err().unwrap();
+ assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn arg_require_group_2() {
+ let m = App::new("arg_require_group")
+ .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr"))
+ .group(ArgGroup::with_name("gr")
+ .arg("some")
+ .arg("other"))
+ .arg(Arg::from_usage("--some 'some arg'"))
+ .arg(Arg::from_usage("--other 'other arg'"))
+ .get_matches_from(vec!["", "-f", "--some"]);
+ assert!(m.is_present("some"));
+ assert!(!m.is_present("other"));
+ assert!(m.is_present("flag"));
+}
+
+#[test]
+fn arg_require_group_3() {
+ let m = App::new("arg_require_group")
+ .arg(Arg::from_usage("-f, --flag 'some flag'").requires("gr"))
+ .group(ArgGroup::with_name("gr")
+ .arg("some")
+ .arg("other"))
+ .arg(Arg::from_usage("--some 'some arg'"))
+ .arg(Arg::from_usage("--other 'other arg'"))
+ .get_matches_from(vec!["", "-f", "--other"]);
+ assert!(!m.is_present("some"));
+ assert!(m.is_present("other"));
+ assert!(m.is_present("flag"));
+}
+
+// REQUIRED_UNLESS
+
+#[test]
+fn issue_753() {
+ let m = App::new("test")
+ .arg(Arg::from_usage("-l, --list 'List available interfaces (and stop there)'"))
+ .arg(Arg::from_usage("-i, --iface=[INTERFACE] 'Ethernet interface for fetching NTP packets'")
+ .required_unless("list"))
+ .arg(Arg::from_usage("-f, --file=[TESTFILE] 'Fetch NTP packets from pcap file'")
+ .conflicts_with("iface")
+ .required_unless("list"))
+ .arg(Arg::from_usage("-s, --server=[SERVER_IP] 'NTP server IP address'")
+ .required_unless("list"))
+ .arg(Arg::from_usage("-p, --port=[SERVER_PORT] 'NTP server port'")
+ .default_value("123"))
+ .get_matches_from_safe(vec!["test", "--list"]);
+ assert!(m.is_ok());
+}
+
+#[test]
+fn required_unless() {
+ let res = App::new("unlesstest")
+ .arg(Arg::with_name("cfg")
+ .required_unless("dbg")
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("dbg").long("debug"))
+ .get_matches_from_safe(vec!["unlesstest", "--debug"]);
+
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("dbg"));
+ assert!(!m.is_present("cfg"));
+}
+
+#[test]
+fn required_unless_err() {
+ let res = App::new("unlesstest")
+ .arg(Arg::with_name("cfg")
+ .required_unless("dbg")
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("dbg").long("debug"))
+ .get_matches_from_safe(vec!["unlesstest"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+// REQUIRED_UNLESS_ALL
+
+#[test]
+fn required_unless_all() {
+ let res = App::new("unlessall")
+ .arg(Arg::with_name("cfg")
+ .required_unless_all(&["dbg", "infile"])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("dbg").long("debug"))
+ .arg(Arg::with_name("infile")
+ .short("i")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["unlessall", "--debug", "-i", "file"]);
+
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("dbg"));
+ assert!(m.is_present("infile"));
+ assert!(!m.is_present("cfg"));
+}
+
+#[test]
+fn required_unless_all_err() {
+ let res = App::new("unlessall")
+ .arg(Arg::with_name("cfg")
+ .required_unless_all(&["dbg", "infile"])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("dbg").long("debug"))
+ .arg(Arg::with_name("infile")
+ .short("i")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["unlessall", "--debug"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+// REQUIRED_UNLESS_ONE
+
+#[test]
+fn required_unless_one() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("cfg")
+ .required_unless_one(&["dbg", "infile"])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("dbg").long("debug"))
+ .arg(Arg::with_name("infile")
+ .short("i")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["unlessone", "--debug"]);
+
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("dbg"));
+ assert!(!m.is_present("cfg"));
+}
+
+#[test]
+fn required_unless_one_2() {
+ // This tests that the required_unless_one works when the second arg in the array is used
+ // instead of the first.
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("cfg")
+ .required_unless_one(&["dbg", "infile"])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("dbg").long("debug"))
+ .arg(Arg::with_name("infile")
+ .short("i")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["unlessone", "-i", "file"]);
+
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(m.is_present("infile"));
+ assert!(!m.is_present("cfg"));
+}
+
+#[test]
+fn required_unless_one_works_with_short() {
+ // GitHub issue: https://github.com/clap-rs/clap/issues/1135
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("a").conflicts_with("b").short("a"))
+ .arg(Arg::with_name("b").short("b"))
+ .arg(
+ Arg::with_name("x")
+ .short("x")
+ .required_unless_one(&["a", "b"])
+ ).get_matches_from_safe(vec!["unlessone", "-a"]);
+
+ assert!(res.is_ok());
+}
+
+#[test]
+fn required_unless_one_works_with_short_err() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("a").conflicts_with("b").short("a"))
+ .arg(Arg::with_name("b").short("b"))
+ .arg(
+ Arg::with_name("x")
+ .short("x")
+ .required_unless_one(&["a", "b"])
+ ).get_matches_from_safe(vec!["unlessone"]);
+
+ assert!(!res.is_ok());
+}
+
+#[test]
+fn required_unless_one_works_without() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("a").conflicts_with("b").short("a"))
+ .arg(Arg::with_name("b").short("b"))
+ .arg(
+ Arg::with_name("x")
+ .required_unless_one(&["a", "b"])
+ ).get_matches_from_safe(vec!["unlessone", "-a"]);
+
+ assert!(res.is_ok());
+}
+
+#[test]
+fn required_unless_one_works_with_long() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("a").conflicts_with("b").short("a"))
+ .arg(Arg::with_name("b").short("b"))
+ .arg(
+ Arg::with_name("x")
+ .long("x_is_the_option")
+ .required_unless_one(&["a", "b"])
+ ).get_matches_from_safe(vec!["unlessone", "-a"]);
+
+ assert!(res.is_ok());
+}
+
+#[test]
+fn required_unless_one_1() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("cfg")
+ .required_unless_one(&["dbg", "infile"])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("dbg").long("debug"))
+ .arg(Arg::with_name("infile")
+ .short("i")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["unlessone", "--debug"]);
+
+ assert!(res.is_ok());
+ let m = res.unwrap();
+ assert!(!m.is_present("infile"));
+ assert!(!m.is_present("cfg"));
+ assert!(m.is_present("dbg"));
+}
+
+#[test]
+fn required_unless_one_err() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("cfg")
+ .required_unless_one(&["dbg", "infile"])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("dbg").long("debug"))
+ .arg(Arg::with_name("infile")
+ .short("i")
+ .takes_value(true))
+ .get_matches_from_safe(vec!["unlessone"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn missing_required_output() {
+ assert!(test::compare_output(test::complex_app(), "clap-test -F", MISSING_REQ, true));
+}
+
+// Conditional external requirements
+
+#[test]
+fn requires_if_present_val() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("cfg")
+ .requires_if("my.cfg", "extra")
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra").long("extra"))
+ .get_matches_from_safe(vec!["unlessone", "--config=my.cfg"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn requires_if_present_mult() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("cfg")
+ .requires_ifs(&[("my.cfg", "extra"), ("other.cfg", "other")])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra").long("extra"))
+ .arg(Arg::with_name("other").long("other"))
+ .get_matches_from_safe(vec!["unlessone", "--config=other.cfg"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn requires_if_present_mult_pass() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("cfg")
+ .requires_ifs(&[("my.cfg", "extra"), ("other.cfg", "other")])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra").long("extra"))
+ .arg(Arg::with_name("other").long("other"))
+ .get_matches_from_safe(vec!["unlessone", "--config=some.cfg"]);
+
+ assert!(res.is_ok());
+ // assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn requires_if_present_val_no_present_pass() {
+ let res = App::new("unlessone")
+ .arg(Arg::with_name("cfg")
+ .requires_if("my.cfg", "extra")
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra").long("extra"))
+ .get_matches_from_safe(vec!["unlessone"]);
+
+ assert!(res.is_ok());
+}
+
+// Conditionally required
+
+#[test]
+fn required_if_val_present_pass() {
+ let res = App::new("ri")
+ .arg(Arg::with_name("cfg")
+ .required_if("extra", "val")
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra")
+ .takes_value(true)
+ .long("extra"))
+ .get_matches_from_safe(vec!["ri", "--extra", "val", "--config", "my.cfg"]);
+
+ assert!(res.is_ok());
+}
+
+#[test]
+fn required_if_val_present_fail() {
+ let res = App::new("ri")
+ .arg(Arg::with_name("cfg")
+ .required_if("extra", "val")
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra")
+ .takes_value(true)
+ .long("extra"))
+ .get_matches_from_safe(vec!["ri", "--extra", "val"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn required_if_val_present_fail_error_output() {
+ let app = App::new("Test app")
+ .version("1.0")
+ .author("F0x06")
+ .about("Arg test")
+ .arg(Arg::with_name("target")
+ .takes_value(true)
+ .required(true)
+ .possible_values(&["file", "stdout"])
+ .long("target"))
+ .arg(Arg::with_name("input")
+ .takes_value(true)
+ .required(true)
+ .long("input"))
+ .arg(Arg::with_name("output")
+ .takes_value(true)
+ .required_if("target", "file")
+ .long("output"));
+
+ assert!(test::compare_output(app,
+ "test --input somepath --target file",
+ COND_REQ_IN_USAGE,
+ true));
+}
+
+#[test]
+fn required_if_wrong_val() {
+ let res = App::new("ri")
+ .arg(Arg::with_name("cfg")
+ .required_if("extra", "val")
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra")
+ .takes_value(true)
+ .long("extra"))
+ .get_matches_from_safe(vec!["ri", "--extra", "other"]);
+
+ assert!(res.is_ok());
+}
+
+#[test]
+fn required_ifs_val_present_pass() {
+ let res = App::new("ri")
+ .arg(Arg::with_name("cfg")
+ .required_ifs(&[("extra", "val"), ("option", "spec")])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("option")
+ .takes_value(true)
+ .long("option"))
+ .arg(Arg::with_name("extra")
+ .takes_value(true)
+ .long("extra"))
+ .get_matches_from_safe(vec!["ri", "--option", "spec", "--config", "my.cfg"]);
+
+ assert!(res.is_ok());
+ // assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn required_ifs_val_present_fail() {
+ let res = App::new("ri")
+ .arg(Arg::with_name("cfg")
+ .required_ifs(&[("extra", "val"), ("option", "spec")])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra")
+ .takes_value(true)
+ .long("extra"))
+ .arg(Arg::with_name("option")
+ .takes_value(true)
+ .long("option"))
+ .get_matches_from_safe(vec!["ri", "--option", "spec"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn required_ifs_wrong_val() {
+ let res = App::new("ri")
+ .arg(Arg::with_name("cfg")
+ .required_ifs(&[("extra", "val"), ("option", "spec")])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra")
+ .takes_value(true)
+ .long("extra"))
+ .arg(Arg::with_name("option")
+ .takes_value(true)
+ .long("option"))
+ .get_matches_from_safe(vec!["ri", "--option", "other"]);
+
+ assert!(res.is_ok());
+}
+
+#[test]
+fn required_ifs_wrong_val_mult_fail() {
+ let res = App::new("ri")
+ .arg(Arg::with_name("cfg")
+ .required_ifs(&[("extra", "val"), ("option", "spec")])
+ .takes_value(true)
+ .long("config"))
+ .arg(Arg::with_name("extra")
+ .takes_value(true)
+ .long("extra"))
+ .arg(Arg::with_name("option")
+ .takes_value(true)
+ .long("option"))
+ .get_matches_from_safe(vec!["ri", "--extra", "other", "--option", "spec"]);
+
+ assert!(res.is_err());
+ assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
+}
+
+#[test]
+fn require_eq() {
+ let app = App::new("clap-test")
+ .version("v1.4.8")
+ .arg(
+ Arg::with_name("opt")
+ .long("opt")
+ .short("o")
+ .required(true)
+ .require_equals(true)
+ .value_name("FILE")
+ .help("some")
+ );
+ assert!(test::compare_output(app, "clap-test", REQUIRE_EQUALS, true));
+}
diff --git a/clap/tests/subcommands.rs b/clap/tests/subcommands.rs
new file mode 100644
index 0000000..6257aaf
--- /dev/null
+++ b/clap/tests/subcommands.rs
@@ -0,0 +1,216 @@
+extern crate clap;
+extern crate regex;
+
+include!("../clap-test.rs");
+
+use clap::{App, Arg, SubCommand, ErrorKind};
+
+static VISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6
+
+USAGE:
+ clap-test [SUBCOMMAND]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test Some help [aliases: dongle, done]";
+
+static INVISIBLE_ALIAS_HELP: &'static str = "clap-test 2.6
+
+USAGE:
+ clap-test [SUBCOMMAND]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test Some help";
+
+#[cfg(feature = "suggestions")]
+static DYM_SUBCMD: &'static str = "error: The subcommand 'subcm' wasn't recognized
+ Did you mean 'subcmd'?
+
+If you believe you received this message in error, try re-running with 'dym -- subcm'
+
+USAGE:
+ dym [SUBCOMMAND]
+
+For more information try --help";
+
+#[test]
+fn subcommand() {
+ let m = App::new("test")
+ .subcommand(SubCommand::with_name("some")
+ .arg(Arg::with_name("test")
+ .short("t")
+ .long("test")
+ .takes_value(true)
+ .help("testing testing")))
+ .arg(Arg::with_name("other").long("other"))
+ .get_matches_from(vec!["myprog", "some", "--test", "testing"]);
+
+ assert_eq!(m.subcommand_name().unwrap(), "some");
+ let sub_m = m.subcommand_matches("some").unwrap();
+ assert!(sub_m.is_present("test"));
+ assert_eq!(sub_m.value_of("test").unwrap(), "testing");
+}
+
+#[test]
+fn subcommand_none_given() {
+ let m = App::new("test")
+ .subcommand(SubCommand::with_name("some")
+ .arg(Arg::with_name("test")
+ .short("t")
+ .long("test")
+ .takes_value(true)
+ .help("testing testing")))
+ .arg(Arg::with_name("other").long("other"))
+ .get_matches_from(vec![""]);
+
+ assert!(m.subcommand_name().is_none());
+}
+
+#[test]
+fn subcommand_multiple() {
+ let m = App::new("test")
+ .subcommands(vec![
+ SubCommand::with_name("some")
+ .arg(Arg::with_name("test")
+ .short("t")
+ .long("test")
+ .takes_value(true)
+ .help("testing testing")),
+ SubCommand::with_name("add")
+ .arg(Arg::with_name("roster").short("r"))
+ ])
+ .arg(Arg::with_name("other").long("other"))
+ .get_matches_from(vec!["myprog", "some", "--test", "testing"]);
+
+ assert!(m.subcommand_matches("some").is_some());
+ assert!(m.subcommand_matches("add").is_none());
+ assert_eq!(m.subcommand_name().unwrap(), "some");
+ let sub_m = m.subcommand_matches("some").unwrap();
+ assert!(sub_m.is_present("test"));
+ assert_eq!(sub_m.value_of("test").unwrap(), "testing");
+}
+
+#[test]
+fn single_alias() {
+ let m = App::new("myprog")
+ .subcommand(SubCommand::with_name("test")
+ .alias("do-stuff"))
+ .get_matches_from(vec!["myprog", "do-stuff"]);
+ assert_eq!(m.subcommand_name(), Some("test"));
+}
+
+#[test]
+fn multiple_aliases() {
+ let m = App::new("myprog")
+ .subcommand(SubCommand::with_name("test")
+ .aliases(&["do-stuff", "test-stuff"]))
+ .get_matches_from(vec!["myprog", "test-stuff"]);
+ assert_eq!(m.subcommand_name(), Some("test"));
+}
+
+#[test]
+#[cfg(feature="suggestions")]
+fn subcmd_did_you_mean_output() {
+ let app = App::new("dym")
+ .subcommand(SubCommand::with_name("subcmd"));
+ assert!(test::compare_output(app, "dym subcm", DYM_SUBCMD, true));
+}
+
+#[test]
+#[cfg(feature="suggestions")]
+fn subcmd_did_you_mean_output_arg() {
+ static EXPECTED: &'static str = "error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context
+\tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?
+
+USAGE:
+ dym [SUBCOMMAND]
+
+For more information try --help";
+
+ let app = App::new("dym")
+ .subcommand(SubCommand::with_name("subcmd")
+ .arg_from_usage("-s --subcmdarg [subcmdarg] 'tests'") );
+ assert!(test::compare_output(app, "dym --subcmarg subcmd", EXPECTED, true));
+}
+
+#[test]
+#[cfg(feature="suggestions")]
+fn subcmd_did_you_mean_output_arg_false_positives() {
+ static EXPECTED: &'static str = "error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context
+
+USAGE:
+ dym [SUBCOMMAND]
+
+For more information try --help";
+
+ let app = App::new("dym")
+ .subcommand(SubCommand::with_name("subcmd")
+ .arg_from_usage("-s --subcmdarg [subcmdarg] 'tests'") );
+ assert!(test::compare_output(app, "dym --subcmarg foo", EXPECTED, true));
+}
+
+#[test]
+fn alias_help() {
+ let m = App::new("myprog")
+ .subcommand(SubCommand::with_name("test")
+ .alias("do-stuff"))
+ .get_matches_from_safe(vec!["myprog", "help", "do-stuff"]);
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
+}
+
+#[test]
+fn visible_aliases_help_output() {
+ let app = App::new("clap-test")
+ .version("2.6")
+ .subcommand(SubCommand::with_name("test")
+ .about("Some help")
+ .alias("invisible")
+ .visible_alias("dongle")
+ .visible_alias("done"));
+ assert!(test::compare_output(app, "clap-test --help", VISIBLE_ALIAS_HELP, false));
+}
+
+#[test]
+fn invisible_aliases_help_output() {
+ let app = App::new("clap-test")
+ .version("2.6")
+ .subcommand(SubCommand::with_name("test")
+ .about("Some help")
+ .alias("invisible"));
+ assert!(test::compare_output(app, "clap-test --help", INVISIBLE_ALIAS_HELP, false));
+}
+
+#[test]
+fn issue_1031_args_with_same_name() {
+ let res = App::new("prog")
+ .arg(Arg::from_usage("--ui-path=<PATH>"))
+ .subcommand(SubCommand::with_name("signer"))
+ .get_matches_from_safe(vec!["prog", "--ui-path", "signer"]);
+
+ assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
+ let m = res.unwrap();
+ assert_eq!(m.value_of("ui-path"), Some("signer"));
+}
+
+#[test]
+fn issue_1031_args_with_same_name_no_more_vals() {
+ let res = App::new("prog")
+ .arg(Arg::from_usage("--ui-path=<PATH>"))
+ .subcommand(SubCommand::with_name("signer"))
+ .get_matches_from_safe(vec!["prog", "--ui-path", "value", "signer"]);
+
+ assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
+ let m = res.unwrap();
+ assert_eq!(m.value_of("ui-path"), Some("value"));
+ assert_eq!(m.subcommand_name(), Some("signer"));
+}
diff --git a/clap/tests/template_help.rs b/clap/tests/template_help.rs
new file mode 100644
index 0000000..b1a546a
--- /dev/null
+++ b/clap/tests/template_help.rs
@@ -0,0 +1,117 @@
+extern crate clap;
+extern crate regex;
+
+use clap::{App, SubCommand};
+
+include!("../clap-test.rs");
+
+static EXAMPLE1_TMPL_S : &'static str = include_str!("example1_tmpl_simple.txt");
+static EXAMPLE1_TMPS_F : &'static str = include_str!("example1_tmpl_full.txt");
+
+static CUSTOM_TEMPL_HELP: &'static str = "MyApp 1.0
+Kevin K. <kbknapp@gmail.com>
+Does awesome things
+
+USAGE:
+ MyApp [FLAGS] [OPTIONS] <output> [SUBCOMMAND]
+
+FLAGS:
+ -d Turn debugging information on
+ -h, --help Prints help information
+ -V, --version Prints version information
+OPTIONS:
+ -c, --config <FILE> Sets a custom config file
+ARGS:
+ <output> Sets an optional output file
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test does testing things";
+
+static SIMPLE_TEMPLATE: &'static str = "MyApp 1.0
+Kevin K. <kbknapp@gmail.com>
+Does awesome things
+
+USAGE:
+ MyApp [FLAGS] [OPTIONS] <output> [SUBCOMMAND]
+
+FLAGS:
+ -d Turn debugging information on
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --config <FILE> Sets a custom config file
+
+ARGS:
+ <output> Sets an optional output file
+
+SUBCOMMANDS:
+ help Prints this message or the help of the given subcommand(s)
+ test does testing things";
+
+#[test]
+fn with_template() {
+ let app = app_example1().template(EXAMPLE1_TMPL_S);
+ assert!(test::compare_output(app, "MyApp --help", SIMPLE_TEMPLATE, false));
+}
+
+#[test]
+fn custom_template() {
+ let app = app_example1().template(EXAMPLE1_TMPS_F);
+ assert!(test::compare_output(app, "MyApp --help", CUSTOM_TEMPL_HELP, false));
+}
+
+#[test]
+fn template_empty() {
+ let app = App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .template("");
+ assert!(test::compare_output(app, "MyApp --help", "", false));
+}
+
+#[test]
+fn template_notag() {
+ let app = App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .template("test no tag test");
+ assert!(test::compare_output(app, "MyApp --help", "test no tag test", false));
+}
+
+#[test]
+fn template_unknowntag() {
+ let app = App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .template("test {unknown_tag} test");
+ assert!(test::compare_output(app, "MyApp --help", "test {unknown_tag} test", false));
+}
+
+#[test]
+fn template_author_version() {
+ let app = App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .template("{author}\n{version}\n{about}\n{bin}");
+ assert!(test::compare_output(app, "MyApp --help", "Kevin K. <kbknapp@gmail.com>\n1.0\nDoes awesome things\nMyApp", false));
+}
+
+// ----------
+
+fn app_example1<'b, 'c>() -> App<'b, 'c> {
+ App::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .args_from_usage("-c, --config=[FILE] 'Sets a custom config file'
+ <output> 'Sets an optional output file'
+ -d... 'Turn debugging information on'")
+ .subcommand(SubCommand::with_name("test")
+ .about("does testing things")
+ .arg_from_usage("-l, --list 'lists test values'"))
+}
diff --git a/clap/tests/tests.rs b/clap/tests/tests.rs
new file mode 100644
index 0000000..0ad825a
--- /dev/null
+++ b/clap/tests/tests.rs
@@ -0,0 +1,435 @@
+#[macro_use]
+extern crate clap;
+extern crate regex;
+
+use std::io::Write;
+use std::str;
+
+include!("../clap-test.rs");
+
+use clap::{App, Arg};
+
+static SCF2OP: &'static str = "flag present 2 times
+option NOT present
+positional NOT present
+flag2 NOT present
+option2 maybe present with value of: Nothing
+positional2 maybe present with value of: Nothing
+option3 NOT present
+positional3 NOT present
+option NOT present
+positional NOT present
+subcmd present
+flag present 2 times
+scoption present with value: some
+An scoption: some
+scpositional present with value: value
+";
+
+static SCFOP: &'static str = "flag present 1 times
+option NOT present
+positional NOT present
+flag2 NOT present
+option2 maybe present with value of: Nothing
+positional2 maybe present with value of: Nothing
+option3 NOT present
+positional3 NOT present
+option NOT present
+positional NOT present
+subcmd present
+flag present 1 times
+scoption present with value: some
+An scoption: some
+scpositional present with value: value
+";
+
+static O2P: &'static str = "flag NOT present
+option present 2 times with value: some
+An option: some
+An option: other
+positional present with value: value
+flag2 NOT present
+option2 maybe present with value of: Nothing
+positional2 maybe present with value of: Nothing
+option3 NOT present
+positional3 NOT present
+option present 2 times with value: some
+An option: some
+An option: other
+positional present with value: value
+subcmd NOT present
+";
+
+static F2OP: &'static str = "flag present 2 times
+option present 1 times with value: some
+An option: some
+positional present with value: value
+flag2 NOT present
+option2 maybe present with value of: Nothing
+positional2 maybe present with value of: Nothing
+option3 NOT present
+positional3 NOT present
+option present 1 times with value: some
+An option: some
+positional present with value: value
+subcmd NOT present
+";
+
+static FOP: &'static str = "flag present 1 times
+option present 1 times with value: some
+An option: some
+positional present with value: value
+flag2 NOT present
+option2 maybe present with value of: Nothing
+positional2 maybe present with value of: Nothing
+option3 NOT present
+positional3 NOT present
+option present 1 times with value: some
+An option: some
+positional present with value: value
+subcmd NOT present
+";
+
+pub fn check_complex_output(args: &str, out: &str) {
+ let mut w = vec![];
+ let matches = test::complex_app().get_matches_from(args.split(' ').collect::<Vec<_>>());
+ if matches.is_present("flag") {
+ writeln!(w, "flag present {} times", matches.occurrences_of("flag")).unwrap();
+ } else {
+ writeln!(w, "flag NOT present").unwrap();
+ }
+
+ if matches.is_present("option") {
+ if let Some(v) = matches.value_of("option") {
+ writeln!(w, "option present {} times with value: {}",matches.occurrences_of("option"), v).unwrap();
+ }
+ if let Some(ov) = matches.values_of("option") {
+ for o in ov {
+ writeln!(w, "An option: {}", o).unwrap();
+ }
+ }
+ } else {
+ writeln!(w, "option NOT present").unwrap();
+ }
+
+ if let Some(p) = matches.value_of("positional") {
+ writeln!(w, "positional present with value: {}", p).unwrap();
+ } else {
+ writeln!(w, "positional NOT present").unwrap();
+ }
+
+ if matches.is_present("flag2") {
+ writeln!(w, "flag2 present").unwrap();
+ writeln!(w, "option2 present with value of: {}", matches.value_of("long-option-2").unwrap()).unwrap();
+ writeln!(w, "positional2 present with value of: {}", matches.value_of("positional2").unwrap()).unwrap();
+ } else {
+ writeln!(w, "flag2 NOT present").unwrap();
+ writeln!(w, "option2 maybe present with value of: {}", matches.value_of("long-option-2").unwrap_or("Nothing")).unwrap();
+ writeln!(w, "positional2 maybe present with value of: {}", matches.value_of("positional2").unwrap_or("Nothing")).unwrap();
+ }
+
+ let _ = match matches.value_of("Option3").unwrap_or("") {
+ "fast" => writeln!(w, "option3 present quickly"),
+ "slow" => writeln!(w, "option3 present slowly"),
+ _ => writeln!(w, "option3 NOT present")
+ };
+
+ let _ = match matches.value_of("positional3").unwrap_or("") {
+ "vi" => writeln!(w, "positional3 present in vi mode"),
+ "emacs" => writeln!(w, "positional3 present in emacs mode"),
+ _ => writeln!(w, "positional3 NOT present")
+ };
+
+ if matches.is_present("option") {
+ if let Some(v) = matches.value_of("option") {
+ writeln!(w, "option present {} times with value: {}",matches.occurrences_of("option"), v).unwrap();
+ }
+ if let Some(ov) = matches.values_of("option") {
+ for o in ov {
+ writeln!(w, "An option: {}", o).unwrap();
+ }
+ }
+ } else {
+ writeln!(w, "option NOT present").unwrap();
+ }
+
+ if let Some(p) = matches.value_of("positional") {
+ writeln!(w, "positional present with value: {}", p).unwrap();
+ } else {
+ writeln!(w, "positional NOT present").unwrap();
+ }
+ if matches.is_present("subcmd") {
+ writeln!(w, "subcmd present").unwrap();
+ if let Some(matches) = matches.subcommand_matches("subcmd") {
+ if matches.is_present("flag") {
+ writeln!(w, "flag present {} times", matches.occurrences_of("flag")).unwrap();
+ } else {
+ writeln!(w, "flag NOT present").unwrap();
+ }
+
+ if matches.is_present("option") {
+ if let Some(v) = matches.value_of("option") {
+ writeln!(w, "scoption present with value: {}", v).unwrap();
+ }
+ if let Some(ov) = matches.values_of("option") {
+ for o in ov {
+ writeln!(w, "An scoption: {}", o).unwrap();
+ }
+ }
+ } else {
+ writeln!(w, "scoption NOT present").unwrap();
+ }
+
+ if let Some(p) = matches.value_of("scpositional") {
+ writeln!(w, "scpositional present with value: {}", p).unwrap();
+ }
+ }
+ } else {
+ writeln!(w, "subcmd NOT present").unwrap();
+ }
+
+ let res = str::from_utf8(&w).unwrap();
+ assert_eq!(res, out);
+}
+
+arg_enum!{
+ #[derive(Debug)]
+ enum Val1 {
+ ValOne,
+ ValTwo
+ }
+}
+arg_enum!{
+ #[derive(Debug)]
+ pub enum Val2 {
+ ValOne,
+ ValTwo
+ }
+}
+arg_enum!{
+ enum Val3 {
+ ValOne,
+ ValTwo
+ }
+}
+arg_enum!{
+ pub enum Val4 {
+ ValOne,
+ ValTwo
+ }
+}
+
+#[test]
+fn test_enums() {
+ let v1_lower = "valone";
+ let v1_camel = "ValOne";
+
+ let v1_lp = v1_lower.parse::<Val1>().unwrap();
+ let v1_cp = v1_camel.parse::<Val1>().unwrap();
+ match v1_lp {
+ Val1::ValOne => (),
+ _ => panic!("Val1 didn't parse correctly"),
+ }
+ match v1_cp {
+ Val1::ValOne => (),
+ _ => panic!("Val1 didn't parse correctly"),
+ }
+ let v1_lp = v1_lower.parse::<Val2>().unwrap();
+ let v1_cp = v1_camel.parse::<Val2>().unwrap();
+ match v1_lp {
+ Val2::ValOne => (),
+ _ => panic!("Val1 didn't parse correctly"),
+ }
+ match v1_cp {
+ Val2::ValOne => (),
+ _ => panic!("Val1 didn't parse correctly"),
+ }
+ let v1_lp = v1_lower.parse::<Val3>().unwrap();
+ let v1_cp = v1_camel.parse::<Val3>().unwrap();
+ match v1_lp {
+ Val3::ValOne => (),
+ _ => panic!("Val1 didn't parse correctly"),
+ }
+ match v1_cp {
+ Val3::ValOne => (),
+ _ => panic!("Val1 didn't parse correctly"),
+ }
+ let v1_lp = v1_lower.parse::<Val4>().unwrap();
+ let v1_cp = v1_camel.parse::<Val4>().unwrap();
+ match v1_lp {
+ Val4::ValOne => (),
+ _ => panic!("Val1 didn't parse correctly"),
+ }
+ match v1_cp {
+ Val4::ValOne => (),
+ _ => panic!("Val1 didn't parse correctly"),
+ }
+}
+
+#[test]
+fn create_app() {
+ let _ =
+ App::new("test").version("1.0").author("kevin").about("does awesome things").get_matches_from(vec![""]);
+}
+
+#[test]
+fn add_multiple_arg() {
+ let _ = App::new("test")
+ .args(&[
+ Arg::with_name("test").short("s"),
+ Arg::with_name("test2").short("l")])
+ .get_matches_from(vec![""]);
+}
+#[test]
+fn flag_x2_opt() {
+ check_complex_output("clap-test value -f -f -o some",
+"flag present 2 times
+option present 1 times with value: some
+An option: some
+positional present with value: value
+flag2 NOT present
+option2 maybe present with value of: Nothing
+positional2 maybe present with value of: Nothing
+option3 NOT present
+positional3 NOT present
+option present 1 times with value: some
+An option: some
+positional present with value: value
+subcmd NOT present
+");
+}
+
+#[test]
+fn long_opt_x2_pos() {
+ check_complex_output("clap-test value --option some --option other", O2P);
+}
+
+#[test]
+fn long_opt_eq_x2_pos() {
+ check_complex_output("clap-test value --option=some --option=other", O2P);
+}
+
+#[test]
+fn short_opt_x2_pos() {
+ check_complex_output("clap-test value -o some -o other", O2P);
+}
+
+#[test]
+fn short_opt_eq_x2_pos() {
+ check_complex_output("clap-test value -o=some -o=other", O2P);
+}
+
+#[test]
+fn short_flag_x2_comb_short_opt_pos() {
+ check_complex_output("clap-test value -ff -o some", F2OP);
+}
+
+#[test]
+fn short_flag_short_opt_pos() {
+ check_complex_output("clap-test value -f -o some", FOP);
+}
+
+#[test]
+fn long_flag_long_opt_pos() {
+ check_complex_output("clap-test value --flag --option some", FOP);
+}
+
+#[test]
+fn long_flag_long_opt_eq_pos() {
+ check_complex_output("clap-test value --flag --option=some", FOP);
+}
+
+#[test]
+fn sc_long_flag_long_opt() {
+ check_complex_output("clap-test subcmd value --flag --option some", SCFOP);
+}
+
+#[test]
+fn sc_long_flag_short_opt_pos() {
+ check_complex_output("clap-test subcmd value --flag -o some", SCFOP);
+}
+
+#[test]
+fn sc_long_flag_long_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value --flag --option=some", SCFOP);
+}
+
+#[test]
+fn sc_short_flag_long_opt_pos() {
+ check_complex_output("clap-test subcmd value -f --option some", SCFOP);
+}
+
+#[test]
+fn sc_short_flag_short_opt_pos() {
+ check_complex_output("clap-test subcmd value -f -o some", SCFOP);
+}
+
+#[test]
+fn sc_short_flag_short_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value -f -o=some", SCFOP);
+}
+
+#[test]
+fn sc_short_flag_long_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value -f --option=some", SCFOP);
+}
+
+#[test]
+fn sc_short_flag_x2_comb_long_opt_pos() {
+ check_complex_output("clap-test subcmd value -ff --option some", SCF2OP);
+}
+
+#[test]
+fn sc_short_flag_x2_comb_short_opt_pos() {
+ check_complex_output("clap-test subcmd value -ff -o some", SCF2OP);
+}
+
+#[test]
+fn sc_short_flag_x2_comb_long_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value -ff --option=some", SCF2OP);
+}
+
+#[test]
+fn sc_short_flag_x2_comb_short_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value -ff -o=some", SCF2OP);
+}
+
+#[test]
+fn sc_long_flag_x2_long_opt_pos() {
+ check_complex_output("clap-test subcmd value --flag --flag --option some", SCF2OP);
+}
+
+#[test]
+fn sc_long_flag_x2_short_opt_pos() {
+ check_complex_output("clap-test subcmd value --flag --flag -o some", SCF2OP);
+}
+
+#[test]
+fn sc_long_flag_x2_short_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value --flag --flag -o=some", SCF2OP);
+}
+
+#[test]
+fn sc_long_flag_x2_long_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value --flag --flag --option=some", SCF2OP);
+}
+
+#[test]
+fn sc_short_flag_x2_long_opt_pos() {
+ check_complex_output("clap-test subcmd value -f -f --option some", SCF2OP);
+}
+
+#[test]
+fn sc_short_flag_x2_short_opt_pos() {
+ check_complex_output("clap-test subcmd value -f -f -o some", SCF2OP);
+}
+
+#[test]
+fn sc_short_flag_x2_short_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value -f -f -o=some", SCF2OP);
+}
+
+#[test]
+fn sc_short_flag_x2_long_opt_eq_pos() {
+ check_complex_output("clap-test subcmd value -f -f --option=some", SCF2OP);
+}
diff --git a/clap/tests/unique_args.rs b/clap/tests/unique_args.rs
new file mode 100644
index 0000000..8710248
--- /dev/null
+++ b/clap/tests/unique_args.rs
@@ -0,0 +1,22 @@
+extern crate clap;
+
+use clap::{App, Arg};
+
+#[test]
+#[should_panic]
+fn unique_arg_names() {
+ App::new("some").args(&[Arg::with_name("arg").short("a"), Arg::with_name("arg").short("b")]);
+}
+
+#[test]
+#[should_panic]
+fn unique_arg_shorts() {
+ App::new("some").args(&[Arg::with_name("arg1").short("a"), Arg::with_name("arg2").short("a")]);
+}
+
+#[test]
+#[should_panic]
+fn unique_arg_longs() {
+ App::new("some")
+ .args(&[Arg::with_name("arg1").long("long"), Arg::with_name("arg2").long("long")]);
+}
diff --git a/clap/tests/utf8.rs b/clap/tests/utf8.rs
new file mode 100644
index 0000000..dfa382e
--- /dev/null
+++ b/clap/tests/utf8.rs
@@ -0,0 +1,223 @@
+#![cfg(not(windows))]
+
+extern crate clap;
+
+use std::ffi::OsString;
+use std::os::unix::ffi::OsStringExt;
+use clap::{App, Arg, AppSettings, ErrorKind};
+
+#[test]
+fn invalid_utf8_strict_positional() {
+ let m = App::new("bad_utf8")
+ .arg(Arg::from_usage("<arg> 'some arg'"))
+ .setting(AppSettings::StrictUtf8)
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
+}
+
+#[test]
+fn invalid_utf8_strict_option_short_space() {
+ let m = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .setting(AppSettings::StrictUtf8)
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from("-a"),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
+}
+
+#[test]
+fn invalid_utf8_strict_option_short_equals() {
+ let m = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .setting(AppSettings::StrictUtf8)
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]);
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
+}
+
+#[test]
+fn invalid_utf8_strict_option_short_no_space() {
+ let m = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .setting(AppSettings::StrictUtf8)
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x61, 0xe9])]);
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
+}
+
+#[test]
+fn invalid_utf8_strict_option_long_space() {
+ let m = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .setting(AppSettings::StrictUtf8)
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from("--arg"),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
+}
+
+#[test]
+fn invalid_utf8_strict_option_long_equals() {
+ let m = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .setting(AppSettings::StrictUtf8)
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]);
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8);
+}
+
+#[test]
+fn invalid_utf8_lossy_positional() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("<arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
+}
+
+#[test]
+fn invalid_utf8_lossy_option_short_space() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from("-a"),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
+}
+
+#[test]
+fn invalid_utf8_lossy_option_short_equals() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
+}
+
+#[test]
+fn invalid_utf8_lossy_option_short_no_space() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x61, 0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
+}
+
+#[test]
+fn invalid_utf8_lossy_option_long_space() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from("--arg"),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
+}
+
+#[test]
+fn invalid_utf8_lossy_option_long_equals() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_lossy("arg").unwrap(), "\u{FFFD}");
+}
+
+#[test]
+fn invalid_utf8_positional() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("<arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9]));
+}
+
+#[test]
+fn invalid_utf8_option_short_space() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from("-a"),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9]));
+}
+
+#[test]
+fn invalid_utf8_option_short_equals() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x61, 0x3d, 0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9]));
+}
+
+#[test]
+fn invalid_utf8_option_short_no_space() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x61, 0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9]));
+}
+
+#[test]
+fn invalid_utf8_option_long_space() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from("--arg"),
+ OsString::from_vec(vec![0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9]));
+}
+
+#[test]
+fn invalid_utf8_option_long_equals() {
+ let r = App::new("bad_utf8")
+ .arg(Arg::from_usage("-a, --arg <arg> 'some arg'"))
+ .get_matches_from_safe(vec![OsString::from(""),
+ OsString::from_vec(vec![0x2d, 0x2d, 0x61, 0x72, 0x67, 0x3d, 0xe9])]);
+ assert!(r.is_ok());
+ let m = r.unwrap();
+ assert!(m.is_present("arg"));
+ assert_eq!(&*m.value_of_os("arg").unwrap(), &*OsString::from_vec(vec![0xe9]));
+}
diff --git a/clap/tests/version-numbers.rs b/clap/tests/version-numbers.rs
new file mode 100644
index 0000000..411eea5
--- /dev/null
+++ b/clap/tests/version-numbers.rs
@@ -0,0 +1,12 @@
+#[macro_use]
+extern crate version_sync;
+
+#[test]
+fn test_readme_deps() {
+ assert_markdown_deps_updated!("README.md");
+}
+
+#[test]
+fn test_html_root_url() {
+ assert_html_root_url_updated!("src/lib.rs");
+}
diff --git a/clap/tests/version.rs b/clap/tests/version.rs
new file mode 100644
index 0000000..8bbd474
--- /dev/null
+++ b/clap/tests/version.rs
@@ -0,0 +1,58 @@
+extern crate clap;
+extern crate regex;
+
+use std::str;
+
+use clap::{App, Arg, ErrorKind};
+
+include!("../clap-test.rs");
+
+static VERSION: &'static str = "clap-test v1.4.8";
+
+#[test]
+fn version_short() {
+ let m = App::new("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.3")
+ .get_matches_from_safe(vec!["myprog", "-V"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::VersionDisplayed);
+}
+
+#[test]
+fn version_long() {
+ let m = App::new("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.3")
+ .get_matches_from_safe(vec!["myprog", "--version"]);
+
+ assert!(m.is_err());
+ assert_eq!(m.unwrap_err().kind, ErrorKind::VersionDisplayed);
+}
+
+#[test]
+fn complex_version_output() {
+ let mut a = App::new("clap-test").version("v1.4.8");
+ let _ = a.get_matches_from_safe_borrow(vec![""]);
+
+ // Now we check the output of print_version()
+ let mut ver = vec![];
+ a.write_version(&mut ver).unwrap();
+ assert_eq!(str::from_utf8(&ver).unwrap(), VERSION);
+}
+
+#[test]
+fn override_ver() {
+ let m = App::new("test")
+ .author("Kevin K.")
+ .about("tests stuff")
+ .version("1.3")
+ .arg(Arg::from_usage("-v, --version 'some version'"))
+ .get_matches_from_safe(vec!["test", "--version"]);
+
+ assert!(m.is_ok());
+ assert!(m.unwrap().is_present("version"));
+}
diff --git a/clap/tests/yaml.rs b/clap/tests/yaml.rs
new file mode 100644
index 0000000..279b987
--- /dev/null
+++ b/clap/tests/yaml.rs
@@ -0,0 +1,40 @@
+#![cfg(feature="yaml")]
+
+#[macro_use]
+extern crate clap;
+
+use clap::App;
+
+#[test]
+fn create_app_from_yaml() {
+ let yml = load_yaml!("app.yml");
+ App::from_yaml(yml);
+}
+
+#[test]
+fn help_message() {
+ let yml = load_yaml!("app.yml");
+ let mut app = App::from_yaml(yml);
+ // Generate the full help message!
+ let _ = app.get_matches_from_safe_borrow(Vec::<String>::new());
+
+ let mut help_buffer = Vec::new();
+ app.write_help(&mut help_buffer).unwrap();
+ let help_string = String::from_utf8(help_buffer).unwrap();
+ assert!(help_string.contains(
+ "-h, --help prints help with a nonstandard description\n"));
+}
+
+#[test]
+fn author() {
+ let yml = load_yaml!("app.yml");
+ let mut app = App::from_yaml(yml);
+ // Generate the full help message!
+ let _ = app.get_matches_from_safe_borrow(Vec::<String>::new());
+
+ let mut help_buffer = Vec::new();
+ app.write_help(&mut help_buffer).unwrap();
+ let help_string = String::from_utf8(help_buffer).unwrap();
+ assert!(help_string.contains(
+ "Kevin K. <kbknapp@gmail.com>"));
+}
diff --git a/heck/.gitignore b/heck/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/heck/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/heck/Cargo.toml b/heck/Cargo.toml
new file mode 100644
index 0000000..93b64e8
--- /dev/null
+++ b/heck/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+authors = ["Without Boats <woboats@gmail.com>"]
+name = "heck"
+version = "0.3.1"
+license = "MIT OR Apache-2.0"
+description = "heck is a case conversion library."
+homepage = "https://github.com/withoutboats/heck"
+repository = "https://github.com/withoutboats/heck"
+documentation = "https://docs.rs/heck"
+keywords = ["string", "case", "camel", "snake", "unicode"]
+readme = "README.md"
+
+[dependencies]
+unicode-segmentation = "1.2.0"
diff --git a/heck/LICENSE-APACHE b/heck/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/heck/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/heck/LICENSE-MIT b/heck/LICENSE-MIT
new file mode 100644
index 0000000..e69282e
--- /dev/null
+++ b/heck/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015 The Rust Project Developers
+
+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/heck/README.md b/heck/README.md
new file mode 100644
index 0000000..cf32337
--- /dev/null
+++ b/heck/README.md
@@ -0,0 +1,56 @@
+# **heck** is a case conversion library
+
+!["I specifically requested the opposite of this."](https://github.com/withoutboats/heck/blob/master/no_step_on_snek.png)
+
+This library exists to provide case conversion between common cases like
+CamelCase and snake_case. It is intended to be unicode aware, internally
+consistent, and reasonably well performing.
+
+## Definition of a word boundary
+
+Word boundaries are defined as the "unicode words" defined in the
+`unicode_segmentation` library, as well as within those words in this manner:
+
+1. All underscore characters are considered word boundaries.
+2. If an uppercase character is followed by lowercase letters, a word boundary
+is considered to be just prior to that uppercase character.
+3. If multiple uppercase characters are consecutive, they are considered to be
+within a single word, except that the last will be part of the next word if it
+is followed by lowercase characters (see rule 2).
+
+That is, "HelloWorld" is segmented `Hello|World` whereas "XMLHttpRequest" is
+segmented `XML|Http|Request`.
+
+Characters not within words (such as spaces, punctuations, and underscores)
+are not included in the output string except as they are a part of the case
+being converted to. Multiple adjacent word boundaries (such as a series of
+underscores) are folded into one. ("hello__world" in snake case is therefore
+"hello_world", not the exact same string). Leading or trailing word boundary
+indicators are dropped, except insofar as CamelCase capitalizes the first word.
+
+### Cases contained in this library:
+
+1. CamelCase
+2. snake_case
+3. kebab-case
+4. SHOUTY_SNAKE_CASE
+5. mixedCase
+6. Title Case
+
+
+### Contributing
+
+PRs of additional well-established cases welcome.
+
+This library is a little bit opinionated (dropping punctuation, for example).
+If that doesn't fit your use case, I hope there is another crate that does. I
+would prefer **not** to receive PRs to make this behavior more configurable.
+
+Bug reports & fixes always welcome. :-)
+
+### License
+
+heck is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See LICENSE-APACHE and LICENSE-MIT for details.
diff --git a/heck/no_step_on_snek.png b/heck/no_step_on_snek.png
new file mode 100644
index 0000000..8aff445
--- /dev/null
+++ b/heck/no_step_on_snek.png
Binary files differ
diff --git a/heck/src/camel.rs b/heck/src/camel.rs
new file mode 100644
index 0000000..74bd741
--- /dev/null
+++ b/heck/src/camel.rs
@@ -0,0 +1,52 @@
+/// This trait defines a camel case conversion.
+///
+/// In CamelCase, word boundaries are indicated by capital letters, including
+/// the first word.
+///
+/// ## Example:
+///
+/// ```rust
+/// extern crate heck;
+/// fn main() {
+///
+/// use heck::CamelCase;
+///
+/// let sentence = "We are not in the least afraid of ruins.";
+/// assert_eq!(sentence.to_camel_case(), "WeAreNotInTheLeastAfraidOfRuins");
+/// }
+/// ```
+pub trait CamelCase: ToOwned {
+ /// Convert this type to camel case.
+ fn to_camel_case(&self) -> Self::Owned;
+}
+
+impl CamelCase for str {
+ fn to_camel_case(&self) -> String {
+ ::transform(self, ::capitalize, |_| {})
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::CamelCase;
+
+ macro_rules! t {
+ ($t:ident : $s1:expr => $s2:expr) => {
+ #[test]
+ fn $t() {
+ assert_eq!($s1.to_camel_case(), $s2)
+ }
+ }
+ }
+
+ t!(test1: "CamelCase" => "CamelCase");
+ t!(test2: "This is Human case." => "ThisIsHumanCase");
+ t!(test3: "MixedUP_CamelCase, with some Spaces" => "MixedUpCamelCaseWithSomeSpaces");
+ t!(test4: "mixed_up_ snake_case, with some _spaces" => "MixedUpSnakeCaseWithSomeSpaces");
+ t!(test5: "kebab-case" => "KebabCase");
+ t!(test6: "SHOUTY_SNAKE_CASE" => "ShoutySnakeCase");
+ t!(test7: "snake_case" => "SnakeCase");
+ t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "ThisContainsAllKindsOfWordBoundaries");
+ t!(test9: "XΣXΣ baffle" => "XσxςBaffle");
+ t!(test10: "XMLHttpRequest" => "XmlHttpRequest");
+}
diff --git a/heck/src/kebab.rs b/heck/src/kebab.rs
new file mode 100644
index 0000000..f81ba92
--- /dev/null
+++ b/heck/src/kebab.rs
@@ -0,0 +1,51 @@
+/// This trait defines a kebab case conversion.
+///
+/// In kebab-case, word boundaries are indicated by hyphens.
+///
+/// ## Example:
+///
+/// ```rust
+/// extern crate heck;
+/// fn main() {
+///
+/// use heck::KebabCase;
+///
+/// let sentence = "We are going to inherit the earth.";
+/// assert_eq!(sentence.to_kebab_case(), "we-are-going-to-inherit-the-earth");
+/// }
+/// ```
+pub trait KebabCase: ToOwned {
+ /// Convert this type to kebab case.
+ fn to_kebab_case(&self) -> Self::Owned;
+}
+
+impl KebabCase for str {
+ fn to_kebab_case(&self) -> Self::Owned {
+ ::transform(self, ::lowercase, |s| s.push('-'))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::KebabCase;
+
+ macro_rules! t {
+ ($t:ident : $s1:expr => $s2:expr) => {
+ #[test]
+ fn $t() {
+ assert_eq!($s1.to_kebab_case(), $s2)
+ }
+ }
+ }
+
+ t!(test1: "CamelCase" => "camel-case");
+ t!(test2: "This is Human case." => "this-is-human-case");
+ t!(test3: "MixedUP CamelCase, with some Spaces" => "mixed-up-camel-case-with-some-spaces");
+ t!(test4: "mixed_up_ snake_case with some _spaces" => "mixed-up-snake-case-with-some-spaces");
+ t!(test5: "kebab-case" => "kebab-case");
+ t!(test6: "SHOUTY_SNAKE_CASE" => "shouty-snake-case");
+ t!(test7: "snake_case" => "snake-case");
+ t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "this-contains-all-kinds-of-word-boundaries");
+ t!(test9: "XΣXΣ baffle" => "xσxς-baffle");
+ t!(test10: "XMLHttpRequest" => "xml-http-request");
+}
diff --git a/heck/src/lib.rs b/heck/src/lib.rs
new file mode 100644
index 0000000..c35ba34
--- /dev/null
+++ b/heck/src/lib.rs
@@ -0,0 +1,165 @@
+//! **heck** is a case conversion library.
+//!
+//! This library exists to provide case conversion between common cases like
+//! CamelCase and snake_case. It is intended to be unicode aware, internally,
+//! consistent, and reasonably well performing.
+//!
+//! ## Definition of a word boundary
+//!
+//! Word boundaries are defined as the "unicode words" defined in the
+//! `unicode_segmentation` library, as well as within those words in this manner:
+//!
+//! 1. All underscore characters are considered word boundaries.
+//! 2. If an uppercase character is followed by lowercase letters, a word boundary
+//! is considered to be just prior to that uppercase character.
+//! 3. If multiple uppercase characters are consecutive, they are considered to be
+//! within a single word, except that the last will be part of the next word if it
+//! is followed by lowercase characters (see rule 2).
+//!
+//! That is, "HelloWorld" is segmented `Hello|World` whereas "XMLHttpRequest" is
+//! segmented `XML|Http|Request`.
+//!
+//! Characters not within words (such as spaces, punctuations, and underscores)
+//! are not included in the output string except as they are a part of the case
+//! being converted to. Multiple adjacent word boundaries (such as a series of
+//! underscores) are folded into one. ("hello__world" in snake case is therefore
+//! "hello_world", not the exact same string). Leading or trailing word boundary
+//! indicators are dropped, except insofar as CamelCase capitalizes the first word.
+//!
+//! ### Cases contained in this library:
+//!
+//! 1. CamelCase
+//! 2. snake_case
+//! 3. kebab-case
+//! 4. SHOUTY_SNAKE_CASE
+//! 5. mixedCase
+//! 6. Title Case
+#![deny(missing_docs)]
+extern crate unicode_segmentation;
+
+mod camel;
+mod kebab;
+mod mixed;
+mod shouty_snake;
+mod snake;
+mod title;
+
+pub use camel::CamelCase;
+pub use kebab::KebabCase;
+pub use mixed::MixedCase;
+pub use shouty_snake::{ShoutySnakeCase, ShoutySnekCase};
+pub use snake::{SnakeCase, SnekCase};
+pub use title::TitleCase;
+
+use unicode_segmentation::UnicodeSegmentation;
+
+fn transform<F, G>(s: &str, with_word: F, boundary: G) -> String
+where
+ F: Fn(&str, &mut String),
+ G: Fn(&mut String)
+{
+
+ /// Tracks the current 'mode' of the transformation algorithm as it scans the input string.
+ ///
+ /// The mode is a tri-state which tracks the case of the last cased character of the current
+ /// word. If there is no cased character (either lowercase or uppercase) since the previous
+ /// word boundary, than the mode is `Boundary`. If the last cased character is lowercase, then
+ /// the mode is `Lowercase`. Othertherwise, the mode is `Uppercase`.
+ #[derive(Clone, Copy, PartialEq)]
+ enum WordMode {
+ /// There have been no lowercase or uppercase characters in the current word.
+ Boundary,
+ /// The previous cased character in the current word is lowercase.
+ Lowercase,
+ /// The previous cased character in the current word is uppercase.
+ Uppercase,
+ }
+
+ let mut out = String::new();
+ let mut first_word = true;
+
+ for word in s.unicode_words() {
+ let mut char_indices = word.char_indices().peekable();
+ let mut init = 0;
+ let mut mode = WordMode::Boundary;
+
+ while let Some((i, c)) = char_indices.next() {
+ // Skip underscore characters
+ if c == '_' {
+ if init == i { init += 1; }
+ continue
+ }
+
+ if let Some(&(next_i, next)) = char_indices.peek() {
+
+ // The mode including the current character, assuming the current character does
+ // not result in a word boundary.
+ let next_mode = if c.is_lowercase() {
+ WordMode::Lowercase
+ } else if c.is_uppercase() {
+ WordMode::Uppercase
+ } else {
+ mode
+ };
+
+ // Word boundary after if next is underscore or current is
+ // not uppercase and next is uppercase
+ if next == '_' || (next_mode == WordMode::Lowercase && next.is_uppercase()) {
+ if !first_word { boundary(&mut out); }
+ with_word(&word[init..next_i], &mut out);
+ first_word = false;
+ init = next_i;
+ mode = WordMode::Boundary;
+
+ // Otherwise if current and previous are uppercase and next
+ // is lowercase, word boundary before
+ } else if mode == WordMode::Uppercase && c.is_uppercase() && next.is_lowercase() {
+ if !first_word { boundary(&mut out); }
+ else { first_word = false; }
+ with_word(&word[init..i], &mut out);
+ init = i;
+ mode = WordMode::Boundary;
+
+ // Otherwise no word boundary, just update the mode
+ } else {
+ mode = next_mode;
+ }
+ } else {
+ // Collect trailing characters as a word
+ if !first_word { boundary(&mut out); }
+ else { first_word = false; }
+ with_word(&word[init..], &mut out);
+ break;
+ }
+ }
+ }
+
+ out
+}
+
+fn lowercase(s: &str, out: &mut String) {
+ let mut chars = s.chars().peekable();
+ while let Some(c) = chars.next() {
+ if c == 'Σ' && chars.peek().is_none() {
+ out.push('ς');
+ } else {
+ out.extend(c.to_lowercase());
+ }
+ }
+}
+
+fn uppercase(s: &str, out: &mut String ) {
+ for c in s.chars() {
+ out.extend(c.to_uppercase())
+ }
+}
+
+fn capitalize(s: &str, out: &mut String) {
+ let mut char_indices = s.char_indices();
+ if let Some((_, c)) = char_indices.next() {
+ out.extend(c.to_uppercase());
+ if let Some((i, _)) = char_indices.next() {
+ lowercase(&s[i..], out);
+ }
+ }
+}
diff --git a/heck/src/mixed.rs b/heck/src/mixed.rs
new file mode 100644
index 0000000..7736684
--- /dev/null
+++ b/heck/src/mixed.rs
@@ -0,0 +1,56 @@
+/// This trait defines a mixed case conversion.
+///
+/// In mixedCase, word boundaries are indicated by capital letters, excepting
+/// the first word.
+///
+/// ## Example:
+///
+/// ```rust
+/// extern crate heck;
+/// fn main() {
+///
+/// use heck::MixedCase;
+///
+/// let sentence = "It is we who built these palaces and cities.";
+/// assert_eq!(sentence.to_mixed_case(), "itIsWeWhoBuiltThesePalacesAndCities");
+/// }
+/// ```
+pub trait MixedCase: ToOwned {
+ /// Convert this type to mixed case.
+ fn to_mixed_case(&self) -> Self::Owned;
+}
+
+impl MixedCase for str {
+ fn to_mixed_case(&self) -> String {
+ ::transform(self, |s, out| {
+ if out.is_empty() { ::lowercase(s, out); }
+ else { ::capitalize(s, out) }
+ }, |_| {})
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::MixedCase;
+
+ macro_rules! t {
+ ($t:ident : $s1:expr => $s2:expr) => {
+ #[test]
+ fn $t() {
+ assert_eq!($s1.to_mixed_case(), $s2)
+ }
+ }
+ }
+
+ t!(test1: "CamelCase" => "camelCase");
+ t!(test2: "This is Human case." => "thisIsHumanCase");
+ t!(test3: "MixedUP CamelCase, with some Spaces" => "mixedUpCamelCaseWithSomeSpaces");
+ t!(test4: "mixed_up_ snake_case, with some _spaces" => "mixedUpSnakeCaseWithSomeSpaces");
+ t!(test5: "kebab-case" => "kebabCase");
+ t!(test6: "SHOUTY_SNAKE_CASE" => "shoutySnakeCase");
+ t!(test7: "snake_case" => "snakeCase");
+ t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "thisContainsAllKindsOfWordBoundaries");
+ t!(test9: "XΣXΣ baffle" => "xσxςBaffle");
+ t!(test10: "XMLHttpRequest" => "xmlHttpRequest");
+ // TODO unicode tests
+}
diff --git a/heck/src/shouty_snake.rs b/heck/src/shouty_snake.rs
new file mode 100644
index 0000000..0f846c3
--- /dev/null
+++ b/heck/src/shouty_snake.rs
@@ -0,0 +1,67 @@
+/// This trait defines a shouty snake case conversion.
+///
+/// In SHOUTY_SNAKE_CASE, word boundaries are indicated by underscores and all
+/// words are in uppercase.
+///
+/// ## Example:
+///
+/// ```rust
+/// extern crate heck;
+/// fn main() {
+///
+/// use heck::ShoutySnakeCase;
+///
+/// let sentence = "That world is growing in this minute.";
+/// assert_eq!(sentence.to_shouty_snake_case(), "THAT_WORLD_IS_GROWING_IN_THIS_MINUTE");
+/// }
+/// ```
+pub trait ShoutySnakeCase: ToOwned {
+ /// Convert this type to shouty snake case.
+ fn to_shouty_snake_case(&self) -> Self::Owned;
+}
+
+/// Oh heck, ShoutySnekCase is an alias for ShoutySnakeCase. See ShoutySnakeCase for
+/// more documentation.
+pub trait ShoutySnekCase: ToOwned {
+ /// CONVERT THIS TYPE TO SNEK CASE.
+ #[allow(non_snake_case)]
+ fn TO_SHOUTY_SNEK_CASE(&self) -> Self::Owned;
+}
+
+impl<T: ?Sized + ShoutySnakeCase> ShoutySnekCase for T {
+ fn TO_SHOUTY_SNEK_CASE(&self) -> Self::Owned {
+ self.to_shouty_snake_case()
+ }
+}
+
+
+impl ShoutySnakeCase for str {
+ fn to_shouty_snake_case(&self) -> Self::Owned {
+ ::transform(self, ::uppercase, |s| s.push('_'))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::ShoutySnakeCase;
+
+ macro_rules! t {
+ ($t:ident : $s1:expr => $s2:expr) => {
+ #[test]
+ fn $t() {
+ assert_eq!($s1.to_shouty_snake_case(), $s2)
+ }
+ }
+ }
+
+ t!(test1: "CamelCase" => "CAMEL_CASE");
+ t!(test2: "This is Human case." => "THIS_IS_HUMAN_CASE");
+ t!(test3: "MixedUP CamelCase, with some Spaces" => "MIXED_UP_CAMEL_CASE_WITH_SOME_SPACES");
+ t!(test4: "mixed_up_snake_case with some _spaces" => "MIXED_UP_SNAKE_CASE_WITH_SOME_SPACES");
+ t!(test5: "kebab-case" => "KEBAB_CASE");
+ t!(test6: "SHOUTY_SNAKE_CASE" => "SHOUTY_SNAKE_CASE");
+ t!(test7: "snake_case" => "SNAKE_CASE");
+ t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "THIS_CONTAINS_ALL_KINDS_OF_WORD_BOUNDARIES");
+ t!(test9: "XΣXΣ baffle" => "XΣXΣ_BAFFLE");
+ t!(test10: "XMLHttpRequest" => "XML_HTTP_REQUEST");
+}
diff --git a/heck/src/snake.rs b/heck/src/snake.rs
new file mode 100644
index 0000000..86c3756
--- /dev/null
+++ b/heck/src/snake.rs
@@ -0,0 +1,79 @@
+/// This trait defines a camel case conversion.
+///
+/// In snake_case, word boundaries are indicated by underscores.
+///
+/// ## Example:
+///
+/// ```rust
+/// extern crate heck;
+/// fn main() {
+///
+/// use heck::SnakeCase;
+///
+/// let sentence = "We carry a new world here, in our hearts.";
+/// assert_eq!(sentence.to_snake_case(), "we_carry_a_new_world_here_in_our_hearts");
+/// }
+/// ```
+pub trait SnakeCase: ToOwned {
+ /// Convert this type to snake case.
+ fn to_snake_case(&self) -> Self::Owned;
+}
+
+/// Oh heck, SnekCase is an alias for SnakeCase. See SnakeCase for
+/// more documentation.
+pub trait SnekCase: ToOwned {
+ /// Convert this type to snek case.
+ fn to_snek_case(&self) -> Self::Owned;
+}
+
+impl<T: ?Sized + SnakeCase> SnekCase for T {
+ fn to_snek_case(&self) -> Self::Owned {
+ self.to_snake_case()
+ }
+}
+
+impl SnakeCase for str {
+ fn to_snake_case(&self) -> String {
+ ::transform(self, ::lowercase, |s| s.push('_'))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::SnakeCase;
+
+ macro_rules! t {
+ ($t:ident : $s1:expr => $s2:expr) => {
+ #[test]
+ fn $t() {
+ assert_eq!($s1.to_snake_case(), $s2)
+ }
+ }
+ }
+
+ t!(test1: "CamelCase" => "camel_case");
+ t!(test2: "This is Human case." => "this_is_human_case");
+ t!(test3: "MixedUP CamelCase, with some Spaces" => "mixed_up_camel_case_with_some_spaces");
+ t!(test4: "mixed_up_ snake_case with some _spaces" => "mixed_up_snake_case_with_some_spaces");
+ t!(test5: "kebab-case" => "kebab_case");
+ t!(test6: "SHOUTY_SNAKE_CASE" => "shouty_snake_case");
+ t!(test7: "snake_case" => "snake_case");
+ t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "this_contains_all_kinds_of_word_boundaries");
+ t!(test9: "XΣXΣ baffle" => "xσxς_baffle");
+ t!(test10: "XMLHttpRequest" => "xml_http_request");
+ t!(test11: "FIELD_NAME11" => "field_name11");
+ t!(test12: "99BOTTLES" => "99bottles");
+ t!(test13: "FieldNamE11" => "field_nam_e11");
+
+ t!(test14: "abc123def456" => "abc123def456");
+ t!(test16: "abc123DEF456" => "abc123_def456");
+ t!(test17: "abc123Def456" => "abc123_def456");
+ t!(test18: "abc123DEf456" => "abc123_d_ef456");
+ t!(test19: "ABC123def456" => "abc123def456");
+ t!(test20: "ABC123DEF456" => "abc123def456");
+ t!(test21: "ABC123Def456" => "abc123_def456");
+ t!(test22: "ABC123DEf456" => "abc123d_ef456");
+ t!(test23: "ABC123dEEf456FOO" => "abc123d_e_ef456_foo");
+ t!(test24: "abcDEF" => "abc_def");
+ t!(test25: "ABcDE" => "a_bc_de");
+}
diff --git a/heck/src/title.rs b/heck/src/title.rs
new file mode 100644
index 0000000..cb48302
--- /dev/null
+++ b/heck/src/title.rs
@@ -0,0 +1,52 @@
+/// This trait defines a title case conversion.
+///
+/// In Title Case, word boundaries are indicated by spaces, and every word is
+/// capitalized.
+///
+/// ## Example:
+///
+/// ```rust
+/// extern crate heck;
+/// fn main() {
+///
+/// use heck::TitleCase;
+///
+/// let sentence = "We have always lived in slums and holes in the wall.";
+/// assert_eq!(sentence.to_title_case(), "We Have Always Lived In Slums And Holes In The Wall");
+/// }
+/// ```
+pub trait TitleCase: ToOwned {
+ /// Convert this type to title case.
+ fn to_title_case(&self) -> Self::Owned;
+}
+
+impl TitleCase for str {
+ fn to_title_case(&self) -> String {
+ ::transform(self, ::capitalize, |s| s.push(' '))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::TitleCase;
+
+ macro_rules! t {
+ ($t:ident : $s1:expr => $s2:expr) => {
+ #[test]
+ fn $t() {
+ assert_eq!($s1.to_title_case(), $s2)
+ }
+ }
+ }
+
+ t!(test1: "CamelCase" => "Camel Case");
+ t!(test2: "This is Human case." => "This Is Human Case");
+ t!(test3: "MixedUP CamelCase, with some Spaces" => "Mixed Up Camel Case With Some Spaces");
+ t!(test4: "mixed_up_ snake_case, with some _spaces" => "Mixed Up Snake Case With Some Spaces");
+ t!(test5: "kebab-case" => "Kebab Case");
+ t!(test6: "SHOUTY_SNAKE_CASE" => "Shouty Snake Case");
+ t!(test7: "snake_case" => "Snake Case");
+ t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "This Contains All Kinds Of Word Boundaries");
+ t!(test9: "XΣXΣ baffle" => "Xσxς Baffle");
+ t!(test10: "XMLHttpRequest" => "Xml Http Request");
+}
diff --git a/nitrocli/CHANGELOG.md b/nitrocli/CHANGELOG.md
index e331f2f..302b3c2 100644
--- a/nitrocli/CHANGELOG.md
+++ b/nitrocli/CHANGELOG.md
@@ -1,3 +1,8 @@
+Unreleased
+----------
+- Reworked argument handling:
+ - Added `structopt` dependency in version `0.3.7`
+
0.3.1
-----
- Added note about interaction with GnuPG to `README` file
diff --git a/nitrocli/Cargo.lock b/nitrocli/Cargo.lock
index 5f2a127..fc87abc 100644
--- a/nitrocli/Cargo.lock
+++ b/nitrocli/Cargo.lock
@@ -17,6 +17,10 @@ name = "base32"
version = "0.4.0"
[[package]]
+name = "bitflags"
+version = "1.2.1"
+
+[[package]]
name = "cc"
version = "1.0.48"
@@ -25,6 +29,15 @@ name = "cfg-if"
version = "0.1.10"
[[package]]
+name = "clap"
+version = "2.33.0"
+dependencies = [
+ "bitflags 1.2.1",
+ "textwrap 0.11.0",
+ "unicode-width 0.1.7",
+]
+
+[[package]]
name = "getrandom"
version = "0.1.13"
dependencies = [
@@ -34,6 +47,13 @@ dependencies = [
]
[[package]]
+name = "heck"
+version = "0.3.1"
+dependencies = [
+ "unicode-segmentation 1.6.0",
+]
+
+[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -57,6 +77,7 @@ dependencies = [
"nitrokey-test 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"nitrokey-test-state 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.3.7",
]
[[package]]
@@ -81,9 +102,9 @@ name = "nitrokey-test"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.7",
+ "quote 1.0.2",
+ "syn 1.0.12",
]
[[package]]
@@ -92,19 +113,39 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "proc-macro-error"
+version = "0.4.4"
+dependencies = [
+ "proc-macro-error-attr 0.4.3",
+ "proc-macro2 1.0.7",
+ "quote 1.0.2",
+ "rustversion 1.0.1",
+ "syn 1.0.12",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "0.4.3"
+dependencies = [
+ "proc-macro2 1.0.7",
+ "quote 1.0.2",
+ "rustversion 1.0.1",
+ "syn 1.0.12",
+ "syn-mid 0.4.0",
+]
+
+[[package]]
name = "proc-macro2"
version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0",
]
[[package]]
name = "quote"
version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.7",
]
[[package]]
@@ -131,13 +172,56 @@ version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "rustversion"
+version = "1.0.1"
+dependencies = [
+ "proc-macro2 1.0.7",
+ "quote 1.0.2",
+ "syn 1.0.12",
+]
+
+[[package]]
+name = "structopt"
+version = "0.3.7"
+dependencies = [
+ "clap 2.33.0",
+ "structopt-derive 0.4.0",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.0"
+dependencies = [
+ "heck 0.3.1",
+ "proc-macro-error 0.4.4",
+ "proc-macro2 1.0.7",
+ "quote 1.0.2",
+ "syn 1.0.12",
+]
+
+[[package]]
name = "syn"
version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.7",
+ "quote 1.0.2",
+ "unicode-xid 0.2.0",
+]
+
+[[package]]
+name = "syn-mid"
+version = "0.4.0"
+dependencies = [
+ "proc-macro2 1.0.7",
+ "quote 1.0.2",
+ "syn 1.0.12",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+dependencies = [
+ "unicode-width 0.1.7",
]
[[package]]
@@ -149,9 +233,16 @@ dependencies = [
]
[[package]]
+name = "unicode-segmentation"
+version = "1.6.0"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.7"
+
+[[package]]
name = "unicode-xid"
version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasi"
@@ -163,11 +254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum nitrokey-test 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3da0c2cedaa512f79fbc3ed45143a52c76c5edcca88d0823b967ff11d05fe37"
"checksum nitrokey-test-state 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a59b732ed6d5212424ed31ec9649f05652bcbc38f45f2292b27a6044e7098803"
-"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
-"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
-"checksum syn 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc157159e2a7df58cd67b1cace10b8ed256a404fb0070593f137d8ba6bef4de"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
-"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
diff --git a/nitrocli/Cargo.toml b/nitrocli/Cargo.toml
index a18cae9..2d5f484 100644
--- a/nitrocli/Cargo.toml
+++ b/nitrocli/Cargo.toml
@@ -55,6 +55,10 @@ version = "0.2"
[dependencies.nitrokey]
version = "0.4.0"
+[dependencies.structopt]
+version = "0.3.7"
+default-features = false
+
[dev-dependencies.nitrokey-test]
version = "0.3.1"
@@ -67,11 +71,27 @@ version = "1"
[patch.crates-io]
argparse = { path = "../argparse" }
base32 = { path = "../base32" }
+bitflags = { path = "../bitflags" }
cc = { path = "../cc" }
cfg-if = { path = "../cfg-if" }
+clap = { path = "../clap" }
getrandom = { path = "../getrandom" }
+heck = { path = "../heck" }
+lazy_static = { path = "../lazy-static" }
libc = { path = "../libc" }
nitrokey = { path = "../nitrokey" }
nitrokey-sys = { path = "../nitrokey-sys" }
-lazy_static = { path = "../lazy-static" }
+proc-macro-error = { path = "../proc-macro-error/proc-macro-error" }
+proc-macro-error-attr = { path = "../proc-macro-error/proc-macro-error-attr" }
+proc-macro2 = { path = "../proc-macro2" }
+quote = { path = "../quote" }
rand_core = { path = "../rand/rand_core" }
+rustversion = { path = "../rustversion" }
+structopt = { path = "../structopt" }
+structopt-derive = { path = "../structopt/structopt-derive" }
+syn = { path = "../syn" }
+syn-mid = { path = "../syn-mid" }
+textwrap = { path = "../textwrap" }
+unicode-segmentation = { path = "../unicode-segmentation" }
+unicode-width = { path = "../unicode-width" }
+unicode-xid = { path = "../unicode-xid" }
diff --git a/proc-macro-error/.gitignore b/proc-macro-error/.gitignore
new file mode 100644
index 0000000..9d538f2
--- /dev/null
+++ b/proc-macro-error/.gitignore
@@ -0,0 +1,4 @@
+/target
+**/*.rs.bk
+Cargo.lock
+.fuse_hidden* \ No newline at end of file
diff --git a/proc-macro-error/.gitlab-ci.yml b/proc-macro-error/.gitlab-ci.yml
new file mode 100644
index 0000000..e36a714
--- /dev/null
+++ b/proc-macro-error/.gitlab-ci.yml
@@ -0,0 +1,54 @@
+stages:
+ - test
+
+
+.setup_template: &setup_template
+ stage: test
+ image: debian:stable-slim
+ before_script:
+ - export CARGO_HOME="$CI_PROJECT_DIR/.cargo"
+ - export PATH="$PATH:$CARGO_HOME/bin"
+ - export RUST_BACKTRACE=full
+ - apt-get update > /dev/null
+ - apt-get install -y curl build-essential > /dev/null
+ - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUST_VERSION
+ - rustup --version
+ - rustc --version
+ - cargo --version
+
+.test_all_template: &test_all_template
+ <<: *setup_template
+ script:
+ - cargo test --all
+
+
+test-stable:
+ <<: *test_all_template
+ variables:
+ RUST_VERSION: stable
+
+test-beta:
+ <<: *test_all_template
+ variables:
+ RUST_VERSION: beta
+
+test-nightly:
+ <<: *test_all_template
+ variables:
+ RUST_VERSION: nightly
+
+
+test-1.31.0:
+ <<: *setup_template
+ script:
+ - cargo test --tests # skip doctests
+ variables:
+ RUST_VERSION: 1.31.0
+
+test-fmt:
+ <<: *setup_template
+ script:
+ - cargo fmt --all -- --check
+ - RUTSFLAGS='--cfg nightly_fmt' cargo fmt --all -- --check
+ variables:
+ RUST_VERSION: stable
diff --git a/proc-macro-error/.travis.yml b/proc-macro-error/.travis.yml
new file mode 100644
index 0000000..362003f
--- /dev/null
+++ b/proc-macro-error/.travis.yml
@@ -0,0 +1,19 @@
+language: rust
+rust:
+ - stable
+ - beta
+ - nightly
+script:
+ - cargo test --all
+matrix:
+ include:
+ - rust: 1.31.0
+ script: cargo test --tests # skip doctests
+ allow_failures:
+ - rust: nightly
+ fast_finish: true
+
+
+notifications:
+ email:
+ on_success: never
diff --git a/proc-macro-error/CHANGELOG.md b/proc-macro-error/CHANGELOG.md
new file mode 100644
index 0000000..29043b5
--- /dev/null
+++ b/proc-macro-error/CHANGELOG.md
@@ -0,0 +1,86 @@
+# v0.4.4 (2019-11-13)
+* Fix `abort_if_dirty` + warnings bug
+* Allow trailing commas in macros
+
+# v0.4.2 (2019-11-7)
+* FINALLY fixed `__pme__suggestions not found` bug
+
+# v0.4.1 (2019-11-7) YANKED
+* Fixed `__pme__suggestions not found` bug
+* Documentation improvements, links checked
+
+# v0.4.0 (2019-11-6) YANKED
+
+## New features
+* "help" messages that can have their own span on nightly, they
+ inherit parent span on stable.
+ ```rust
+ let cond_help = if condition { Some("some help message") else { None } };
+ abort!(
+ span, // parent span
+ "something's wrong, {} wrongs in total", 10; // main message
+ help = "here's a help for you, {}", "take it"; // unconditional help message
+ help =? cond_help; // conditional help message, must be Option
+ note = note_span => "don't forget the note, {}", "would you?" // notes can have their own span but it's effective only on nightly
+ )
+ ```
+* Warnings via `emit_warning` and `emit_warning_call_site`. Nightly only, they're ignored on stable.
+* Now `proc-macro-error` delegates to `proc_macro::Diagnostic` on nightly.
+
+## Breaking changes
+* `MacroError` is now replaced by `Diagnostic`. Its API resembles `proc_macro::Diagnostic`.
+* `Diagnostic` does not implement `From<&str/String>` so `Result<T, &str/String>::abort_or_exit()`
+ won't work anymore (nobody used it anyway).
+* `macro_error!` macro is replaced with `diagnostic!`.
+
+## Improvements
+* Now `proc-macro-error` renders notes exactly just like rustc does.
+* We don't parse a body of a function annotated with `#[proc_macro_error]` anymore,
+ only looking at the signature. This should somewhat decrease expansion time for large functions.
+
+# v0.3.3 (2019-10-16)
+* Now you can use any word instead of "help", undocumented.
+
+# v0.3.2 (2019-10-16)
+* Introduced support for "help" messages, undocumented.
+
+# v0.3.0 (2019-10-8)
+
+## The crate has been completely rewritten from scratch!
+
+## Changes (most are breaking):
+* Renamed macros:
+ * `span_error` => `abort`
+ * `call_site_error` => `abort_call_site`
+* `filter_macro_errors` was replaced by `#[proc_macro_error]` attribute.
+* `set_dummy` now takes `TokenStream` instead of `Option<TokenStream>`
+* Support for multiple errors via `emit_error` and `emit_call_site_error`
+* New `macro_error` macro for building errors in format=like style.
+* `MacroError` API had been reconsidered. It also now implements `quote::ToTokens`.
+
+# v0.2.6 (2019-09-02)
+* Introduce support for dummy implementations via `dummy::set_dummy`
+* `multi::*` is now deprecated, will be completely rewritten in v0.3
+
+# v0.2.0 (2019-08-15)
+
+## Breaking changes
+* `trigger_error` replaced with `MacroError::trigger` and `filter_macro_error_panics`
+ is hidden from docs.
+ This is not quite a breaking change since users weren't supposed to use these functions directly anyway.
+* All dependencies are updated to `v1.*`.
+
+## New features
+* Ability to stack multiple errors via `multi::MultiMacroErrors` and emit them at once.
+
+## Improvements
+* Now `MacroError` implements `std::fmt::Display` instead of `std::string::ToString`.
+* `MacroError::span` inherent method.
+* `From<MacroError> for proc_macro/proc_macro2::TokenStream` implementations.
+* `AsRef/AsMut<String> for MacroError` implementations.
+
+# v0.1.x (2019-07-XX)
+
+## New features
+* An easy way to report errors inside within a proc-macro via `span_error`,
+ `call_site_error` and `filter_macro_errors`.
diff --git a/proc-macro-error/Cargo.toml b/proc-macro-error/Cargo.toml
new file mode 100644
index 0000000..6fa600e
--- /dev/null
+++ b/proc-macro-error/Cargo.toml
@@ -0,0 +1,7 @@
+[workspace]
+
+members = [
+ "proc-macro-error",
+ "proc-macro-error-attr",
+ "test-crate",
+]
diff --git a/proc-macro-error/LICENSE-APACHE b/proc-macro-error/LICENSE-APACHE
new file mode 100644
index 0000000..52ba334
--- /dev/null
+++ b/proc-macro-error/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright 2019 CreepySkeleton <creepy-skeleton@yandex.ru>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/proc-macro-error/LICENSE-MIT b/proc-macro-error/LICENSE-MIT
new file mode 100644
index 0000000..d01f775
--- /dev/null
+++ b/proc-macro-error/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 CreepySkeleton
+
+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/proc-macro-error/README.md b/proc-macro-error/README.md
new file mode 100644
index 0000000..d6d1086
--- /dev/null
+++ b/proc-macro-error/README.md
@@ -0,0 +1,206 @@
+# proc-macro-error
+
+[![travis ci](https://travis-ci.org/CreepySkeleton/proc-macro-error.svg?branch=master)](https://travis-ci.org/CreepySkeleton/proc-macro-error)
+[![docs.rs](https://docs.rs/proc-macro-error/badge.svg)](https://docs.rs/proc-macro-error)
+
+This crate aims to make error reporting in proc-macros simple and easy to use.
+Migrate from `panic!`-based errors for as little effort as possible!
+
+Also, there's ability to [append a dummy token stream][crate::dummy] to your errors.
+
+```toml
+[dependencies]
+proc-macro-error = "0.4"
+```
+
+*Supports rustc 1.31 and up*
+
+[Documentation and guide][guide]
+
+## What emitted errors look like
+
+```
+error: multiple error part: multi2
+
+ = note: help message test
+ = help: Option help test
+ = note: I see what you did here...
+
+ --> $DIR/multi-error.rs:4:18
+ |
+4 | make_fn!(multi1, multi2, _, multi3);
+ | ^^^^^^
+```
+
+## Examples
+
+### Panic-like usage
+
+```rust
+use proc_macro_error::*;
+use proc_macro::TokenStream;
+use syn::{DeriveInput, parse_macro_input};
+use quote::quote;
+
+// This is your main entry point
+#[proc_macro]
+// this attribute *MUST* be placed on top of the #[proc_macro] function
+#[proc_macro_error]
+pub fn make_answer(input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+
+ if let Err(err) = some_logic(&input) {
+ // we've got a span to blame, let's use it
+ // This immediately aborts the proc-macro and shows the error
+ abort!(err.span, "You made an error, go fix it: {}", err.msg);
+ }
+
+ // `Result` has some handy shortcuts if your error type implements
+ // `Into<MacroError>`. `Option` has one unconditionally.
+ more_logic(&input).expect_or_abort("What a careless user, behave!");
+
+ if !more_logic_for_logic_god(&input) {
+ // We don't have an exact location this time,
+ // so just highlight the proc-macro invocation itself
+ abort_call_site!(
+ "Bad, bad user! Now go stand in the corner and think about what you did!");
+ }
+
+ // Now all the processing is done, return `proc_macro::TokenStream`
+ quote!(/* stuff */).into()
+}
+```
+
+### `proc_macro::Diagnostic`-like usage
+
+```rust
+use proc_macro_error::*;
+use proc_macro::TokenStream;
+use syn::{spanned::Spanned, DeriveInput, ItemStruct, Fields, Attribute , parse_macro_input};
+use quote::quote;
+
+fn process_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
+ attrs
+ .iter()
+ .filter_map(|attr| match process_attr(attr) {
+ Ok(res) => Some(res),
+ Err(msg) => {
+ emit_error!(attr.span(), "Invalid attribute: {}", msg);
+ None
+ }
+ })
+ .collect()
+}
+
+fn process_fields(_attrs: &Fields) -> Vec<TokenStream> {
+ // processing fields in pretty much the same way as attributes
+ unimplemented!()
+}
+
+#[proc_macro]
+#[proc_macro_error]
+pub fn make_answer(input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as ItemStruct);
+ let attrs = process_attrs(&input.attrs);
+
+ // abort right now if some errors were encountered
+ // at the attributes processing stage
+ abort_if_dirty();
+
+ let fields = process_fields(&input.fields);
+
+ // no need to think about emitted errors
+ // #[proc_macro_error] will handle them for you
+ //
+ // just return a TokenStream as you normally would
+ quote!(/* stuff */).into()
+}
+```
+
+## Limitations
+
+- Warnings are emitted only on nightly, they're ignored on stable.
+- "help" suggestions cannot have their own span info on stable, (they inherit parent span).
+- If a panic occurs somewhere in your macro no errors will be displayed. This is not a
+ technical limitation but intentional design, `panic` is not for error reporting.
+
+## MSRV policy
+
+`proc_macro_error` will always be compatible with proc-macro holy trinity:
+`proc_macro2`, `syn`, `quote` crates. In other words, if the trinity is available
+to you than `proc_macro_error` is available too.
+
+## Motivation
+
+Error handling in proc-macros sucks. There's not much of a choice today:
+you either "bubble up" the error up to the top-level of your macro and convert it to
+a [`compile_error!`][compl_err] invocation or just use a good old panic. Both these ways suck:
+
+- Former sucks because it's quite redundant to unroll a proper error handling
+ just for critical errors that will crash the macro anyway so people mostly
+ choose not to bother with it at all and use panic. Almost nobody does it,
+ simple `.expect` is too tempting.
+
+ Also, if you do decide to implement this `Result`-based architecture in your macro
+ you're going to have to rewrite it entirely once [`proc_macro::Diagnostic`][] is finally stable.
+ Not cool.
+
+- Later sucks because there's no way to carry out span info via `panic!`. `rustc` will highlight
+ the whole invocation itself but not some specific token inside it.
+
+ Furthermore, panics aren't for error-reporting at all; panics are for bug-detecting
+ (like unwrapping on `None` or out-of-range indexing) or for early development stages
+ when you need a prototype ASAP and error handling can wait. Mixing these usages only
+ messes things up.
+
+- There is [`proc_macro::Diagnostic`][] which is awesome but it has been experimental
+ for more than a year and is unlikely to be stabilized any time soon.
+
+ This crate's API is intentionally designed to be compatible with `proc_macro::Diagnostic`
+ and delegates to it whenever possible. Once `Diagnostics` is stable this crate
+ will **always** delegate to it, no code changes will be required on user side.
+
+That said, we need a solution, but this solution must meet these conditions:
+
+- It must be better than `panic!`. The main point: it must offer a way to carry span information
+ over to user.
+- It must take as little effort as possible to migrate from `panic!`. Ideally, a new
+ macro with the same semantics plus ability to carry out span info. We should also keep
+ in mind the existence of [`proc_macro::Diagnostic`][] .
+- **It must be usable on stable**.
+
+This crate aims to provide such a mechanism. All you have to do is annotate your top-level
+`#[proc_macro]` function with `#[proc_macro_errors]` attribute and change panics to
+[`abort!`]/[`abort_call_site!`] where appropriate, see [the Guide][guide].
+
+## Disclaimer
+Please note that **this crate is not intended to be used in any way other
+than proc-macro error reporting**, use `Result` and `?` for anything else.
+
+<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>
+
+
+[compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html
+[`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html
+
+[crate::dummy]: https://docs.rs/proc-macro-error/0.4/proc_macro_error/dummy/index.html
+[crate::multi]: https://docs.rs/proc-macro-error/0.4/proc_macro_error/multi/index.html
+
+[`abort_call_site!`]: https://docs.rs/proc-macro-error/0.4/proc_macro_error/macro.abort_call_site.html
+[`abort!`]: https://docs.rs/proc-macro-error/0.4/proc_macro_error/macro.abort.html
+[guide]: https://docs.rs/proc-macro-error
diff --git a/proc-macro-error/proc-macro-error-attr/Cargo.toml b/proc-macro-error/proc-macro-error-attr/Cargo.toml
new file mode 100644
index 0000000..6dee68e
--- /dev/null
+++ b/proc-macro-error/proc-macro-error-attr/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "proc-macro-error-attr"
+version = "0.4.3"
+authors = ["CreepySkeleton <creepy-skeleton@yandex.ru>"]
+edition = "2018"
+description = "attribute macro for proc-macro-error crate"
+license = "MIT OR Apache-2.0"
+repository = "https://gitlab.com/CreepySkeleton/proc-macro-error"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+quote = "1"
+proc-macro2 = "1"
+syn = { version = "1", default-features = false, features = ["derive", "parsing", "proc-macro"] }
+syn-mid = "0.4"
+rustversion = "1.0"
diff --git a/proc-macro-error/proc-macro-error-attr/src/lib.rs b/proc-macro-error/proc-macro-error-attr/src/lib.rs
new file mode 100644
index 0000000..3c1013b
--- /dev/null
+++ b/proc-macro-error/proc-macro-error-attr/src/lib.rs
@@ -0,0 +1,162 @@
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use proc_macro2::Ident;
+use quote::quote;
+use std::iter::FromIterator;
+use syn::{
+ parse::{Parse, ParseStream},
+ parse_macro_input,
+ punctuated::Punctuated,
+ Attribute, Token,
+};
+use syn_mid::{Block, ItemFn};
+
+use self::Setting::*;
+
+#[proc_macro_attribute]
+pub fn proc_macro_error(attr: TokenStream, input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as ItemFn);
+ let mut settings = match syn::parse::<Settings>(attr) {
+ Ok(settings) => settings,
+ Err(err) => {
+ let err = err.to_compile_error();
+ return quote!(#input #err).into();
+ }
+ };
+
+ let is_proc_macro = is_proc_macro(&input.attrs);
+ if is_proc_macro {
+ settings.set(AssertUnwindSafe);
+ }
+
+ if detect_proc_macro_hack(&input.attrs) {
+ settings.set(ProcMacroHack);
+ }
+
+ if !(settings.is_set(AllowNotMacro) || is_proc_macro) {
+ return quote!(
+ #input
+ compile_error!("#[proc_macro_error] attribute can be used only with a proc-macro\n\n \
+ hint: if you are really sure that #[proc_macro_error] should be applied \
+ to this exact function use #[proc_macro_error(allow_not_macro)]\n");
+ )
+ .into();
+ }
+
+ let ItemFn {
+ attrs,
+ vis,
+ constness,
+ asyncness,
+ unsafety,
+ abi,
+ fn_token,
+ ident,
+ generics,
+ inputs,
+ output,
+ block,
+ ..
+ } = input;
+
+ let body = gen_body(block, settings);
+
+ quote!(
+ #(#attrs)*
+ #vis
+ #constness
+ #asyncness
+ #unsafety
+ #abi
+ #fn_token
+ #ident
+ #generics
+ (#inputs)
+ #output
+
+ { #body }
+ )
+ .into()
+}
+
+#[derive(PartialEq)]
+enum Setting {
+ AssertUnwindSafe,
+ AllowNotMacro,
+ ProcMacroHack,
+}
+
+impl Parse for Setting {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let ident: Ident = input.parse()?;
+ match &*ident.to_string() {
+ "assert_unwind_safe" => Ok(AssertUnwindSafe),
+ "allow_not_macro" => Ok(AllowNotMacro),
+ "proc_macro_hack" => Ok(ProcMacroHack),
+ _ => Err(syn::Error::new(
+ ident.span(),
+ format!(
+ "unknown setting `{}`, expected one of \
+ `assert_unwind_safe`, `allow_not_macro`, `proc_macro_hack`",
+ ident
+ ),
+ )),
+ }
+ }
+}
+
+struct Settings(Vec<Setting>);
+impl Parse for Settings {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let punct = Punctuated::<Setting, Token![,]>::parse_terminated(input)?;
+ Ok(Settings(Vec::from_iter(punct)))
+ }
+}
+
+impl Settings {
+ fn is_set(&self, setting: Setting) -> bool {
+ self.0.iter().any(|s| *s == setting)
+ }
+
+ fn set(&mut self, setting: Setting) {
+ self.0.push(setting)
+ }
+}
+
+#[rustversion::since(1.37)]
+fn gen_body(block: Block, settings: Settings) -> proc_macro2::TokenStream {
+ let is_proc_macro_hack = settings.is_set(ProcMacroHack);
+ let closure = if settings.is_set(AssertUnwindSafe) {
+ quote!(::std::panic::AssertUnwindSafe(|| #block ))
+ } else {
+ quote!(|| #block)
+ };
+
+ quote!( ::proc_macro_error::entry_point(#closure, #is_proc_macro_hack) )
+}
+
+// FIXME:
+// proc_macro::TokenStream does not implement UnwindSafe until 1.37.0.
+// Considering this is the closure's return type the unwind safety check would fail
+// for virtually every closure possible, the check is meaningless.
+#[rustversion::before(1.37)]
+fn gen_body(block: Block, settings: Settings) -> proc_macro2::TokenStream {
+ let is_proc_macro_hack = settings.is_set(ProcMacroHack);
+ let closure = quote!(::std::panic::AssertUnwindSafe(|| #block ));
+ quote!( ::proc_macro_error::entry_point(#closure, #is_proc_macro_hack) )
+}
+
+fn detect_proc_macro_hack(attrs: &[Attribute]) -> bool {
+ attrs
+ .iter()
+ .any(|attr| attr.path.is_ident("proc_macro_hack"))
+}
+
+fn is_proc_macro(attrs: &[Attribute]) -> bool {
+ attrs.iter().any(|attr| {
+ attr.path.is_ident("proc_macro")
+ || attr.path.is_ident("proc_macro_derive")
+ || attr.path.is_ident("proc_macro_attribute")
+ })
+}
diff --git a/proc-macro-error/proc-macro-error/Cargo.toml b/proc-macro-error/proc-macro-error/Cargo.toml
new file mode 100644
index 0000000..2da213a
--- /dev/null
+++ b/proc-macro-error/proc-macro-error/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "proc-macro-error"
+version = "0.4.4"
+authors = ["CreepySkeleton <creepy-skeleton@yandex.ru>"]
+description = "Almost drop-in replacement to panics in proc-macros"
+
+repository = "https://gitlab.com/CreepySkeleton/proc-macro-error"
+readme = "../README.md"
+keywords = ["proc-macro", "error", "errors"]
+categories = ["development-tools::procedural-macro-helpers"]
+license = "MIT OR Apache-2.0"
+
+edition = "2018"
+build = "build.rs"
+
+[badges]
+maintenance = { status = "actively-developed" }
+
+[dependencies]
+quote = "1"
+proc-macro2 = "1"
+syn = { version = "1", default-features = false }
+proc-macro-error-attr = { path = "../proc-macro-error-attr", version = "0.4.3"}
+
+[build-dependencies]
+rustversion = "1.0"
diff --git a/proc-macro-error/proc-macro-error/build.rs b/proc-macro-error/proc-macro-error/build.rs
new file mode 100644
index 0000000..04ddc11
--- /dev/null
+++ b/proc-macro-error/proc-macro-error/build.rs
@@ -0,0 +1,11 @@
+#[rustversion::nightly]
+fn nightly() {
+ println!("cargo:rustc-cfg=pme_nightly");
+}
+
+#[rustversion::not(nightly)]
+fn nightly() {}
+
+fn main() {
+ nightly()
+}
diff --git a/proc-macro-error/proc-macro-error/src/dummy.rs b/proc-macro-error/proc-macro-error/src/dummy.rs
new file mode 100644
index 0000000..f7443b3
--- /dev/null
+++ b/proc-macro-error/proc-macro-error/src/dummy.rs
@@ -0,0 +1,136 @@
+//! Facility to emit dummy implementations (or whatever) in case
+//! an error happen.
+//!
+//! `compile_error!` does not abort a compilation right away. This means
+//! `rustc` doesn't just show you the error and abort, it carries on the
+//! compilation process looking for other errors to report.
+//!
+//! Let's consider an example:
+//!
+//! ```rust,ignore
+//! use proc_macro::TokenStream;
+//! use proc_macro_error::*;
+//!
+//! trait MyTrait {
+//! fn do_thing();
+//! }
+//!
+//! // this proc macro is supposed to generate MyTrait impl
+//! #[proc_macro_derive(MyTrait)]
+//! #[proc_macro_error]
+//! fn example(input: TokenStream) -> TokenStream {
+//! // somewhere deep inside
+//! abort!(span, "something's wrong");
+//!
+//! // this implementation will be generated if no error happened
+//! quote! {
+//! impl MyTrait for #name {
+//! fn do_thing() {/* whatever */}
+//! }
+//! }
+//! }
+//!
+//! // ================
+//! // in main.rs
+//!
+//! // this derive triggers an error
+//! #[derive(MyTrait)] // first BOOM!
+//! struct Foo;
+//!
+//! fn main() {
+//! Foo::do_thing(); // second BOOM!
+//! }
+//! ```
+//!
+//! The problem is: the generated token stream contains only `compile_error!`
+//! invocation, the impl was not generated. That means user will see two compilation
+//! errors:
+//!
+//! ```text
+//! error: something's wrong
+//! --> $DIR/probe.rs:9:10
+//! |
+//! 9 |#[proc_macro_derive(MyTrait)]
+//! | ^^^^^^^
+//!
+//! error[E0599]: no function or associated item named `do_thing` found for type `Foo` in the current scope
+//! --> src\main.rs:3:10
+//! |
+//! 1 | struct Foo;
+//! | ----------- function or associated item `do_thing` not found for this
+//! 2 | fn main() {
+//! 3 | Foo::do_thing(); // second BOOM!
+//! | ^^^^^^^^ function or associated item not found in `Foo`
+//! ```
+//!
+//! But the second error is meaningless! We definitely need to fix this.
+//!
+//! Most used approach in cases like this is "dummy implementation" -
+//! omit `impl MyTrait for #name` and fill functions bodies with `unimplemented!()`.
+//!
+//! This is how you do it:
+//!
+//! ```rust,ignore
+//! use proc_macro::TokenStream;
+//! use proc_macro_error::*;
+//!
+//! trait MyTrait {
+//! fn do_thing();
+//! }
+//!
+//! // this proc macro is supposed to generate MyTrait impl
+//! #[proc_macro_derive(MyTrait)]
+//! #[proc_macro_error]
+//! fn example(input: TokenStream) -> TokenStream {
+//! // first of all - we set a dummy impl which will be appended to
+//! // `compile_error!` invocations in case a trigger does happen
+//! set_dummy(quote! {
+//! impl MyTrait for #name {
+//! fn do_thing() { unimplemented!() }
+//! }
+//! });
+//!
+//! // somewhere deep inside
+//! abort!(span, "something's wrong");
+//!
+//! // this implementation will be generated if no error happened
+//! quote! {
+//! impl MyTrait for #name {
+//! fn do_thing() {/* whatever */}
+//! }
+//! }
+//! }
+//!
+//! // ================
+//! // in main.rs
+//!
+//! // this derive triggers an error
+//! #[derive(MyTrait)] // first BOOM!
+//! struct Foo;
+//!
+//! fn main() {
+//! Foo::do_thing(); // no more errors!
+//! }
+//! ```
+
+use proc_macro2::TokenStream;
+use std::cell::Cell;
+
+use crate::check_correctness;
+
+thread_local! {
+ static DUMMY_IMPL: Cell<Option<TokenStream>> = Cell::new(None);
+}
+
+/// Sets dummy token stream which will be appended to `compile_error!(msg);...`
+/// invocations in case you'll emit any errors.
+///
+/// See [guide](../index.html#guide).
+pub fn set_dummy(dummy: TokenStream) -> Option<TokenStream> {
+ check_correctness();
+ DUMMY_IMPL.with(|old_dummy| old_dummy.replace(Some(dummy)))
+}
+
+pub(crate) fn cleanup() -> Option<TokenStream> {
+ DUMMY_IMPL.with(|old_dummy| old_dummy.replace(None))
+}
diff --git a/proc-macro-error/proc-macro-error/src/lib.rs b/proc-macro-error/proc-macro-error/src/lib.rs
new file mode 100644
index 0000000..5fb0223
--- /dev/null
+++ b/proc-macro-error/proc-macro-error/src/lib.rs
@@ -0,0 +1,514 @@
+//! # proc-macro-error
+//!
+//! This crate aims to make error reporting in proc-macros simple and easy to use.
+//! Migrate from `panic!`-based errors for as little effort as possible!
+//!
+//! Also, there's ability to [append a dummy token stream](dummy/index.html) to your errors.
+//!
+//! ## Limitations
+//!
+//! - Warnings are emitted only on nightly, they're ignored on stable.
+//! - "help" suggestions cannot have their own span info on stable, (they inherit parent span).
+//! - If a panic occurs somewhere in your macro no errors will be displayed. This is not a
+//! technical limitation but intentional design, `panic` is not for error reporting.
+//!
+//! ## Guide
+//!
+//! ### Macros
+//!
+//! First of all - **all the emitting-related API must be used within a function
+//! annotated with [`#[proc_macro_error]`](#proc_macro_error-attribute) attribute**. You'll just get a
+//! panic otherwise, no errors will be shown.
+//!
+//! For most of the time you will be using macros.
+//!
+//! - [`abort!`]:
+//!
+//! Very much panic-like usage - abort execution and show the error. Expands to [`!`] (never type).
+//!
+//! - [`abort_call_site!`]:
+//!
+//! Shortcut for `abort!(Span::call_site(), ...)`. Expands to [`!`] (never type).
+//!
+//! - [`emit_error!`]:
+//!
+//! [`proc_macro::Diagnostic`]-like usage - emit the error but do not abort the macro.
+//! The compilation will fail nonetheless. Expands to [`()`] (unit type).
+//!
+//! - [`emit_call_site_error!`]:
+//!
+//! Shortcut for `emit_error!(Span::call_site(), ...)`. Expands to [`()`] (unit type).
+//!
+//! - [`emit_warning!`]:
+//!
+//! Like `emit_error!` but emit a warning instead of error. The compilation won't fail
+//! because of warnings.
+//! Expands to [`()`] (unit type).
+//!
+//! **Beware**: warnings are nightly only, they are completely ignored on stable.
+//!
+//! - [`emit_call_site_warning!`]:
+//!
+//! Shortcut for `emit_warning!(Span::call_site(), ...)`. Expands to `()` (unit type).
+//!
+//! - [`diagnostic`]:
+//!
+//! Build instance of `Diagnostic` in format-like style.
+//!
+//! ### Syntax
+//!
+//! All the macros have pretty much the same syntax:
+//!
+//! 1. ```ignore
+//! abort!(single_expr)
+//! ```
+//! Shortcut for `Diagnostic::from().abort()`
+//!
+//! 2. ```ignore
+//! abort!(span, message)
+//! ```
+//! Shortcut for `Diagnostic::spanned(span, message.to_string()).abort()`
+//!
+//! 3. ```ignore
+//! abort!(span, format_literal, format_args...)
+//! ```
+//! Shortcut for `Diagnostic::spanned(span, format!(format_literal, format_args...)).abort()`
+//!
+//! That's it. `abort!`, `emit_warning`, `emit_error` share this exact syntax.
+//! `abort_call_site!`, `emit_call_site_warning`, `emit_call_site_error` lack 1 form
+//! and do not take span in 2 and 3 forms.
+//!
+//! `diagnostic!` require `Level` instance between `span` and second argument (1 form is the same).
+//!
+//! #### Note attachments
+//!
+//! 3. Every macro can have "note" attachments (only 2 and 3 form).
+//! ```ignore
+//! let opt_help = if have_some_info { Some("did you mean `this`?") } else { None };
+//!
+//! abort!(
+//! span, message; // <--- attachments start with `;` (semicolon)
+//!
+//! help = "format {} {}", "arg1", "arg2"; // <--- every attachment ends with `;`,
+//! // maybe except the last one
+//!
+//! note = "to_string"; // <--- one arg uses `.to_string()` instead of `format!()`
+//!
+//! yay = "I see what {} did here", "you"; // <--- "help =" and "hint =" are mapped to Diagnostic::help
+//! // anything else is Diagnostic::note
+//!
+//! wow = note_span => "custom span"; // <--- attachments can have their own span
+//! // it takes effect only on nightly though
+//!
+//! hint =? opt_help; // <-- "optional" attachment, get displayed only if `Some`
+//! // must be single `Option` expression
+//!
+//! note =? note_span => opt_help // <-- optional attachments can have custom spans too
+//! )
+//! ```
+//!
+//! ### `#[proc_macro_error]` attribute
+//!
+//! **This attribute MUST be present on the top level of your macro.**
+//!
+//! This attribute performs the setup and cleanup necessary to make things work.
+//!
+//! #### Syntax
+//!
+//! `#[proc_macro_error]` or `#[proc_macro_error(settings...)]`, where `settings...`
+//! is a comma-separated list of:
+//!
+//! - `proc_macro_hack`:
+//!
+//! To correctly cooperate with `#[proc_macro_hack]` `#[proc_macro_error]`
+//! attribute must be placed *before* (above) it, like this:
+//!
+//! ```ignore
+//! #[proc_macro_error]
+//! #[proc_macro_hack]
+//! #[proc_macro]
+//! fn my_macro(input: TokenStream) -> TokenStream {
+//! unimplemented!()
+//! }
+//! ```
+//!
+//! If, for some reason, you can't place it like that you can use
+//! `#[proc_macro_error(proc_macro_hack)]` instead.
+//!
+//! - `allow_not_macro`:
+//!
+//! By default, the attribute checks that it's applied to a proc-macro.
+//! If none of `#[proc_macro]`, `#[proc_macro_derive]` nor `#[proc_macro_attribute]` are
+//! present it will panic. It's the intention - this crate is supposed to be used only with
+//! proc-macros. This setting is made to bypass the check, useful in certain
+//! circumstances.
+//!
+//! Please note: the function this attribute is applied to must return `proc_macro::TokenStream`.
+//!
+//! - `assert_unwind_safe`:
+//!
+//! By default, your code must be [unwind safe]. If your code is not unwind safe but you believe
+//! it's correct you can use this setting to bypass the check. This is typically needed
+//! for code that uses `lazy_static` or `thread_local` with `Cell/RefCell` inside.
+//!
+//! This setting is implied if `#[proc_macro_error]` is applied to a function
+//! marked as `#[proc_macro]`, `#[proc_macro_derive]` or `#[proc_macro_attribute]`.
+//!
+//! ### Diagnostic type
+//!
+//! [`Diagnostic`] type is intentionally designed to be API compatible with [`proc_macro::Diagnostic`].
+//! Not all API is implemented, only the part that can be reasonably implemented on stable.
+//!
+//!
+//! [`abort!`]: macro.abort.html
+//! [`emit_warning!`]: macro.emit_warning.html
+//! [`emit_error!`]: macro.emit_error.html
+//! [`abort_call_site!`]: macro.abort_call_site.html
+//! [`emit_call_site_warning!`]: macro.emit_call_site_error.html
+//! [`emit_call_site_error!`]: macro.emit_call_site_warning.html
+//! [`diagnostic!`]: macro.diagnostic.html
+//! [proc_macro_error]: ./../proc_macro_error_attr/attr.proc_macro_error.html
+//! [`Diagnostic`]: struct.Diagnostic.html
+//! [`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html
+//! [unwind safe]: https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html#what-is-unwind-safety
+//! [`!`]: https://doc.rust-lang.org/std/primitive.never.html
+//! [`()`]: https://doc.rust-lang.org/std/primitive.unit.html
+
+#![cfg_attr(pme_nightly, feature(proc_macro_diagnostic))]
+#![forbid(unsafe_code)]
+
+// reexports for use in macros
+#[doc(hidden)]
+pub extern crate proc_macro;
+#[doc(hidden)]
+pub extern crate proc_macro2;
+
+pub use self::dummy::set_dummy;
+pub use proc_macro_error_attr::proc_macro_error;
+
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use quote::{quote_spanned, ToTokens};
+use std::cell::Cell;
+use std::panic::{catch_unwind, resume_unwind, UnwindSafe};
+
+pub mod dummy;
+
+mod macros;
+
+#[cfg(not(any(pme_nightly, nightly_fmt)))]
+#[path = "stable.rs"]
+mod imp;
+
+#[cfg(any(pme_nightly, nightly_fmt))]
+#[path = "nightly.rs"]
+mod imp;
+
+/// Represents a diagnostic level
+///
+/// # Warnings
+///
+/// Warnings are ignored on stable/beta
+#[derive(Debug, PartialEq)]
+pub enum Level {
+ Error,
+ Warning,
+ #[doc(hidden)]
+ NonExhaustive,
+}
+
+/// Represents a single diagnostic message
+#[derive(Debug)]
+pub struct Diagnostic {
+ level: Level,
+ span: Span,
+ msg: String,
+ suggestions: Vec<(SuggestionKind, String, Option<Span>)>,
+}
+
+/// This traits expands `Result<T, Into<Diagnostic>>` with some handy shortcuts.
+pub trait ResultExt {
+ type Ok;
+
+ /// Behaves like `Result::unwrap`: if self is `Ok` yield the contained value,
+ /// otherwise abort macro execution via `abort!`.
+ fn unwrap_or_abort(self) -> Self::Ok;
+
+ /// Behaves like `Result::expect`: if self is `Ok` yield the contained value,
+ /// otherwise abort macro execution via `abort!`.
+ /// If it aborts then resulting error message will be preceded with `message`.
+ fn expect_or_abort(self, msg: &str) -> Self::Ok;
+}
+
+/// This traits expands `Option` with some handy shortcuts.
+pub trait OptionExt {
+ type Some;
+
+ /// Behaves like `Option::expect`: if self is `Some` yield the contained value,
+ /// otherwise abort macro execution via `abort_call_site!`.
+ /// If it aborts the `message` will be used for [`compile_error!`][compl_err] invocation.
+ ///
+ /// [compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html
+ fn expect_or_abort(self, msg: &str) -> Self::Some;
+}
+
+impl Diagnostic {
+ /// Create a new diagnostic message that points to `Span::call_site()`
+ pub fn new(level: Level, message: String) -> Self {
+ Diagnostic::spanned(Span::call_site(), level, message)
+ }
+
+ /// Create a new diagnostic message that points to the `span`
+ pub fn spanned(span: Span, level: Level, message: String) -> Self {
+ Diagnostic {
+ level,
+ span,
+ msg: message,
+ suggestions: vec![],
+ }
+ }
+
+ /// Attach a "help" note to your main message, note will have it's own span on nightly.
+ ///
+ /// # Span
+ ///
+ /// The span is ignored on stable, the note effectively inherits its parent's (main message) span
+ pub fn span_help(mut self, span: Span, msg: String) -> Self {
+ self.suggestions
+ .push((SuggestionKind::Help, msg, Some(span)));
+ self
+ }
+
+ /// Attach a "help" note to your main message,
+ pub fn help(mut self, msg: String) -> Self {
+ self.suggestions.push((SuggestionKind::Help, msg, None));
+ self
+ }
+
+ /// Attach a note to your main message, note will have it's own span on nightly.
+ ///
+ /// # Span
+ ///
+ /// The span is ignored on stable, the note effectively inherits its parent's (main message) span
+ pub fn span_note(mut self, span: Span, msg: String) -> Self {
+ self.suggestions
+ .push((SuggestionKind::Note, msg, Some(span)));
+ self
+ }
+
+ /// Attach a note to your main message
+ pub fn note(mut self, msg: String) -> Self {
+ self.suggestions.push((SuggestionKind::Note, msg, None));
+ self
+ }
+
+ /// The message of main warning/error (no notes attached)
+ pub fn message(&self) -> &str {
+ &self.msg
+ }
+
+ /// Abort the proc-macro's execution and display the diagnostic.
+ ///
+ /// # Warnings
+ ///
+ /// Warnings do not get emitted on stable/beta but this function will abort anyway.
+ pub fn abort(self) -> ! {
+ self.emit();
+ abort_now()
+ }
+
+ /// Display the diagnostic while not aborting macro execution.
+ ///
+ /// # Warnings
+ ///
+ /// Warnings are ignored on stable/beta
+ pub fn emit(self) {
+ imp::emit_diagnostic(self);
+ }
+}
+
+/// Abort macro execution and display all the emitted errors, if any.
+///
+/// Does nothing if no errors were emitted (warnings do not count).
+pub fn abort_if_dirty() {
+ imp::abort_if_dirty();
+}
+
+#[doc(hidden)]
+impl Diagnostic {
+ pub fn span_suggestion(self, span: Span, suggestion: &str, msg: String) -> Self {
+ match suggestion {
+ "help" | "hint" => self.span_help(span, msg),
+ _ => self.span_note(span, msg),
+ }
+ }
+
+ pub fn suggestion(self, suggestion: &str, msg: String) -> Self {
+ match suggestion {
+ "help" | "hint" => self.help(msg),
+ _ => self.note(msg),
+ }
+ }
+}
+
+impl ToTokens for Diagnostic {
+ fn to_tokens(&self, ts: &mut TokenStream) {
+ use std::borrow::Cow;
+
+ fn ensure_lf(buf: &mut String, s: &str) {
+ if s.ends_with('\n') {
+ buf.push_str(s);
+ } else {
+ buf.push_str(s);
+ buf.push('\n');
+ }
+ }
+
+ let Diagnostic {
+ ref msg,
+ ref suggestions,
+ ref level,
+ ..
+ } = *self;
+
+ if *level == Level::Warning {
+ return;
+ }
+
+ let message = if suggestions.is_empty() {
+ Cow::Borrowed(msg)
+ } else {
+ let mut message = String::new();
+ ensure_lf(&mut message, msg);
+ message.push('\n');
+
+ for (kind, note, _span) in suggestions {
+ message.push_str(" = ");
+ message.push_str(kind.name());
+ message.push_str(": ");
+ ensure_lf(&mut message, note);
+ }
+ message.push('\n');
+
+ Cow::Owned(message)
+ };
+
+ let span = &self.span;
+ let msg = syn::LitStr::new(&*message, *span);
+ ts.extend(quote_spanned!(*span=> compile_error!(#msg); ));
+ }
+}
+
+impl<T, E: Into<Diagnostic>> ResultExt for Result<T, E> {
+ type Ok = T;
+
+ fn unwrap_or_abort(self) -> T {
+ match self {
+ Ok(res) => res,
+ Err(e) => e.into().abort(),
+ }
+ }
+
+ fn expect_or_abort(self, message: &str) -> T {
+ match self {
+ Ok(res) => res,
+ Err(e) => {
+ let mut e = e.into();
+ e.msg = format!("{}: {}", message, e.msg);
+ e.abort()
+ }
+ }
+ }
+}
+
+impl<T> OptionExt for Option<T> {
+ type Some = T;
+
+ fn expect_or_abort(self, message: &str) -> T {
+ match self {
+ Some(res) => res,
+ None => abort_call_site!(message),
+ }
+ }
+}
+
+#[derive(Debug)]
+enum SuggestionKind {
+ Help,
+ Note,
+}
+
+impl SuggestionKind {
+ fn name(&self) -> &'static str {
+ match self {
+ SuggestionKind::Note => "note",
+ SuggestionKind::Help => "help",
+ }
+ }
+}
+
+impl From<syn::Error> for Diagnostic {
+ fn from(e: syn::Error) -> Self {
+ Diagnostic::spanned(e.span(), Level::Error, e.to_string())
+ }
+}
+
+/// This is the entry point for a proc-macro.
+///
+/// **NOT PUBLIC API, SUBJECT TO CHANGE WITHOUT ANY NOTICE**
+#[doc(hidden)]
+pub fn entry_point<F>(f: F, proc_macro_hack: bool) -> proc_macro::TokenStream
+where
+ F: FnOnce() -> proc_macro::TokenStream + UnwindSafe,
+{
+ ENTERED_ENTRY_POINT.with(|flag| flag.set(true));
+ let caught = catch_unwind(f);
+ let dummy = dummy::cleanup();
+ let err_storage = imp::cleanup();
+ ENTERED_ENTRY_POINT.with(|flag| flag.set(false));
+
+ let mut appendix = TokenStream::new();
+ if proc_macro_hack {
+ appendix.extend(quote! {
+ #[allow(unused)]
+ macro_rules! proc_macro_call {
+ () => ( unimplemented!() )
+ }
+ });
+ }
+
+ match caught {
+ Ok(ts) => {
+ if err_storage.is_empty() {
+ ts
+ } else {
+ quote!( #(#err_storage)* #dummy #appendix ).into()
+ }
+ }
+
+ Err(boxed) => match boxed.downcast::<AbortNow>() {
+ Ok(_) => quote!( #(#err_storage)* #dummy #appendix ).into(),
+ Err(boxed) => resume_unwind(boxed),
+ },
+ }
+}
+
+fn abort_now() -> ! {
+ check_correctness();
+ panic!(AbortNow)
+}
+
+thread_local! {
+ static ENTERED_ENTRY_POINT: Cell<bool> = Cell::new(false);
+}
+
+struct AbortNow;
+
+fn check_correctness() {
+ if !ENTERED_ENTRY_POINT.with(|flag| flag.get()) {
+ panic!(
+ "proc-macro-error API cannot be used outside of `entry_point` invocation, \
+ perhaps you forgot to annotate your #[proc_macro] function with `#[proc_macro_error]"
+ );
+ }
+}
diff --git a/proc-macro-error/proc-macro-error/src/macros.rs b/proc-macro-error/proc-macro-error/src/macros.rs
new file mode 100644
index 0000000..117612c
--- /dev/null
+++ b/proc-macro-error/proc-macro-error/src/macros.rs
@@ -0,0 +1,257 @@
+// FIXME: this can be greatly simplified via $()?
+// as soon as MRSV hits 1.32
+
+/// Build [`Diagnostic`](struct.Diagnostic.html) instance from provided arguments.
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! diagnostic {
+ // from alias
+ ($err:expr) => { $crate::Diagnostic::from($err) };
+
+ // span, message, help
+ ($span:expr, $level:expr, $fmt:expr, $($args:expr),+ ; $($rest:tt)+) => {{
+ let diag = $crate::Diagnostic::spanned(
+ $span.into(),
+ $level,
+ format!($fmt, $($args),*)
+ );
+ $crate::__pme__suggestions!(diag $($rest)*);
+ diag
+ }};
+
+ ($span:expr, $level:expr, $msg:expr ; $($rest:tt)+) => {{
+ let diag = $crate::Diagnostic::spanned($span.into(), $level, $msg.to_string());
+ $crate::__pme__suggestions!(diag $($rest)*);
+ diag
+ }};
+
+ // span, message, no help
+ ($span:expr, $level:expr, $fmt:expr, $($args:expr),+) => {{
+ $crate::Diagnostic::spanned(
+ $span.into(),
+ $level,
+ format!($fmt, $($args),*)
+ )
+ }};
+
+ ($span:expr, $level:expr, $msg:expr) => {{
+ $crate::Diagnostic::spanned($span.into(), $level, $msg.to_string())
+ }};
+
+
+ // trailing commas
+
+ ($span:expr, $level:expr, $fmt:expr, $($args:expr),+, ; $($rest:tt)+) => {
+ $crate::diagnostic!($span, $level, $fmt, $($args),* ; $($rest)*)
+ };
+ ($span:expr, $level:expr, $msg:expr, ; $($rest:tt)+) => {
+ $crate::diagnostic!($span, $level, $msg ; $($rest)*)
+ };
+ ($span:expr, $level:expr, $fmt:expr, $($args:expr),+,) => {
+ $crate::diagnostic!($span, $level, $fmt, $($args),*)
+ };
+ ($span:expr, $level:expr, $msg:expr,) => {
+ $crate::diagnostic!($span, $level, $msg)
+ };
+ // ($err:expr,) => { $crate::diagnostic!($err) };
+}
+
+/// Abort proc-macro execution right now and display the error.
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+#[macro_export]
+macro_rules! abort {
+ ($err:expr) => {
+ $crate::diagnostic!($err).abort()
+ };
+
+ ($span:expr, $($tts:tt)*) => {
+ $crate::diagnostic!($span, $crate::Level::Error, $($tts)*).abort()
+ };
+}
+
+/// Shortcut for `abort!(Span::call_site(), msg...)`. This macro
+/// is still preferable over plain panic, panics are not for error reporting.
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! abort_call_site {
+ ($($tts:tt)*) => {
+ $crate::diagnostic!(
+ $crate::proc_macro2::Span::call_site(),
+ $crate::Level::Error,
+ $($tts)*
+ ).abort()
+ };
+}
+
+/// Emit an error while not aborting the proc-macro right away.
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! emit_error {
+ ($err:expr) => {
+ $crate::diagnostic!($err).emit()
+ };
+
+ ($span:expr, $($tts:tt)*) => {{
+ let level = $crate::Level::Error;
+ $crate::diagnostic!($span, level, $($tts)*).emit()
+ }};
+}
+
+/// Shortcut for `emit_error!(Span::call_site(), ...)`. This macro
+/// is still preferable over plain panic, panics are not for error reporting..
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! emit_call_site_error {
+ ($($tts:tt)*) => {
+ $crate::diagnostic!(
+ $crate::proc_macro2::Span()::call_site(),
+ $crate::Level::Error,
+ $($tts)*
+ ).emit()
+ };
+}
+
+/// Emit a warning. Warnings are not errors and compilation won't fail because of them.
+///
+/// **Does nothing on stable**
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! emit_warning {
+ ($span:expr, $($tts:tt)*) => {
+ $crate::diagnostic!($span, $crate::Level::Warning, $($tts)*).emit()
+ };
+}
+
+/// Shortcut for `emit_warning!(Span::call_site(), ...)`.
+///
+/// **Does nothing on stable**
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! emit_call_site_warning {
+ ($($tts:tt)*) => {{
+ let span = $crate::proc_macro2::Span()::call_site();
+ $crate::diagnostic!(span, $crate::Level::Warning, $($tts)*).emit()
+ }};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __pme__suggestions {
+ ($var:ident) => ();
+
+ ($var:ident $help:ident =? $msg:expr) => {
+ let $var = if let Some(msg) = $msg {
+ $var.suggestion(stringify!($help), msg.to_string())
+ } else {
+ $var
+ };
+ };
+ ($var:ident $help:ident =? $span:expr => $msg:expr) => {
+ let $var = if let Some(msg) = $msg {
+ $var.span_suggestion($span.into(), stringify!($help), msg.to_string())
+ } else {
+ $var
+ };
+ };
+
+ ($var:ident $help:ident =? $msg:expr ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help =? $msg);
+ $crate::__pme__suggestions!($var $($rest)*);
+ };
+ ($var:ident $help:ident =? $span:expr => $msg:expr ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help =? $span => $msg);
+ $crate::__pme__suggestions!($var $($rest)*);
+ };
+
+
+ ($var:ident $help:ident = $msg:expr) => {
+ let $var = $var.suggestion(stringify!($help), $msg.to_string());
+ };
+ ($var:ident $help:ident = $fmt:expr, $($args:expr),+) => {
+ let $var = $var.suggestion(
+ stringify!($help),
+ format!($fmt, $($args),*)
+ );
+ };
+ ($var:ident $help:ident = $span:expr => $msg:expr) => {
+ let $var = $var.span_suggestion($span.into(), stringify!($help), $msg.to_string());
+ };
+ ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+) => {
+ let $var = $var.span_suggestion(
+ $span.into(),
+ stringify!($help),
+ format!($fmt, $($args),*)
+ );
+ };
+
+ ($var:ident $help:ident = $msg:expr ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help = $msg);
+ $crate::__pme__suggestions!($var $($rest)*);
+ };
+ ($var:ident $help:ident = $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help = $fmt, $($args),*);
+ $crate::__pme__suggestions!($var $($rest)*);
+ };
+ ($var:ident $help:ident = $span:expr => $msg:expr ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help = $span => $msg);
+ $crate::__pme__suggestions!($var $($rest)*);
+ };
+ ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*);
+ $crate::__pme__suggestions!($var $($rest)*);
+ };
+
+ // trailing commas
+
+ ($var:ident $help:ident = $msg:expr,) => {
+ $crate::__pme__suggestions!($var $help = $msg)
+ };
+ ($var:ident $help:ident = $fmt:expr, $($args:expr),+,) => {
+ $crate::__pme__suggestions!($var $help = $fmt, $($args)*)
+ };
+ ($var:ident $help:ident = $span:expr => $msg:expr,) => {
+ $crate::__pme__suggestions!($var $help = $span => $msg)
+ };
+ ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),*,) => {
+ $crate::__pme__suggestions!($var $help = $span => $fmt, $($args)*)
+ };
+ ($var:ident $help:ident = $msg:expr, ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help = $msg; $($rest)*)
+ };
+ ($var:ident $help:ident = $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help = $fmt, $($args),*; $($rest)*)
+ };
+ ($var:ident $help:ident = $span:expr => $msg:expr, ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help = $span => $msg; $($rest)*)
+ };
+ ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => {
+ $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*; $($rest)*)
+ };
+}
diff --git a/proc-macro-error/proc-macro-error/src/nightly.rs b/proc-macro-error/proc-macro-error/src/nightly.rs
new file mode 100644
index 0000000..d053c2f
--- /dev/null
+++ b/proc-macro-error/proc-macro-error/src/nightly.rs
@@ -0,0 +1,49 @@
+use std::sync::atomic::{AtomicBool, Ordering};
+
+use proc_macro::{Diagnostic as PDiag, Level as PLevel};
+
+use crate::{abort_now, check_correctness, Diagnostic, Level, SuggestionKind};
+
+pub fn abort_if_dirty() {
+ check_correctness();
+ if IS_DIRTY.load(Ordering::SeqCst) {
+ abort_now()
+ }
+}
+
+pub(crate) fn cleanup() -> Vec<Diagnostic> {
+ vec![]
+}
+
+pub(crate) fn emit_diagnostic(diag: Diagnostic) {
+ let Diagnostic {
+ level,
+ span,
+ msg,
+ suggestions,
+ } = diag;
+
+ let level = match level {
+ Level::Warning => PLevel::Warning,
+ Level::Error => {
+ IS_DIRTY.store(true, Ordering::SeqCst);
+ PLevel::Error
+ }
+ _ => unreachable!(),
+ };
+
+ let mut res = PDiag::spanned(span.unwrap(), level, msg);
+
+ for (kind, msg, span) in suggestions {
+ res = match (kind, span) {
+ (SuggestionKind::Note, Some(span)) => res.span_note(span.unwrap(), msg),
+ (SuggestionKind::Help, Some(span)) => res.span_help(span.unwrap(), msg),
+ (SuggestionKind::Note, None) => res.note(msg),
+ (SuggestionKind::Help, None) => res.help(msg),
+ }
+ }
+
+ res.emit()
+}
+
+static IS_DIRTY: AtomicBool = AtomicBool::new(false);
diff --git a/proc-macro-error/proc-macro-error/src/stable.rs b/proc-macro-error/proc-macro-error/src/stable.rs
new file mode 100644
index 0000000..07042d3
--- /dev/null
+++ b/proc-macro-error/proc-macro-error/src/stable.rs
@@ -0,0 +1,26 @@
+use std::cell::RefCell;
+
+use crate::{abort_now, check_correctness, Diagnostic, Level};
+
+pub fn abort_if_dirty() {
+ check_correctness();
+ ERR_STORAGE.with(|storage| {
+ if !storage.borrow().is_empty() {
+ abort_now()
+ }
+ });
+}
+
+pub(crate) fn cleanup() -> Vec<Diagnostic> {
+ ERR_STORAGE.with(|storage| storage.replace(Vec::new()))
+}
+
+pub(crate) fn emit_diagnostic(diag: Diagnostic) {
+ if diag.level == Level::Error {
+ ERR_STORAGE.with(|storage| storage.borrow_mut().push(diag));
+ }
+}
+
+thread_local! {
+ static ERR_STORAGE: RefCell<Vec<Diagnostic>> = RefCell::new(Vec::new());
+}
diff --git a/proc-macro-error/test-crate/Cargo.toml b/proc-macro-error/test-crate/Cargo.toml
new file mode 100644
index 0000000..96dadc3
--- /dev/null
+++ b/proc-macro-error/test-crate/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "test-crate"
+version = "0.0.0"
+authors = ["CreepySkeleton <creepy-skeleton@yandex.ru>"]
+edition = "2018"
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro-error = { path = "../proc-macro-error"}
+quote = "1"
+proc-macro2 = "1"
+syn = {version = "1", default-features = false }
+
+[dev-dependencies]
+trybuild = "1.0"
+rustversion = "1.0"
+toml = "=0.5.2" # DO NOT BUMP
diff --git a/proc-macro-error/test-crate/src/lib.rs b/proc-macro-error/test-crate/src/lib.rs
new file mode 100644
index 0000000..2ea9175
--- /dev/null
+++ b/proc-macro-error/test-crate/src/lib.rs
@@ -0,0 +1,123 @@
+#[macro_use]
+extern crate proc_macro_error;
+#[macro_use]
+extern crate syn;
+extern crate proc_macro;
+
+use proc_macro2::Span;
+use proc_macro_error::{set_dummy, Level, OptionExt, ResultExt};
+use syn::{
+ parse::{Parse, ParseStream},
+ punctuated::Punctuated,
+ spanned::Spanned,
+ Ident,
+};
+
+struct IdentOrUnderscore {
+ span: Span,
+ part: String,
+}
+
+impl IdentOrUnderscore {
+ fn new(span: Span, part: String) -> Self {
+ IdentOrUnderscore { span, part }
+ }
+}
+
+impl Parse for IdentOrUnderscore {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let la = input.lookahead1();
+
+ if la.peek(Ident) {
+ let t = input.parse::<Ident>().unwrap();
+ Ok(IdentOrUnderscore::new(t.span(), t.to_string()))
+ } else if la.peek(Token![_]) {
+ let t = input.parse::<Token![_]>().unwrap();
+ Ok(IdentOrUnderscore::new(t.span(), "_".to_string()))
+ } else {
+ Err(la.error())
+ }
+ }
+}
+
+struct Args(Vec<IdentOrUnderscore>);
+
+impl Parse for Args {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let args = Punctuated::<_, Token![,]>::parse_terminated(input)?;
+ Ok(Args(args.into_iter().collect()))
+ }
+}
+
+#[proc_macro]
+#[proc_macro_error]
+pub fn make_fn(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let mut name = String::new();
+ let input = parse_macro_input!(input as Args);
+
+ for arg in input.0 {
+ match &*arg.part {
+ "abort" => abort!(
+ arg.span,
+ "abort! 3{} args {}", "+", "test";
+ hint = "help {} test", "message"
+ ),
+
+ "abort_call_site" => abort_call_site!(
+ "abort_call_site! 2{} args {}", "+", "test";
+ help = "help {} test", "message"
+ ),
+
+ "direct_abort" => {
+ diagnostic!(arg.span, Level::Error, "direct MacroError::abort() test").abort()
+ }
+
+ "result_expect" => {
+ let e = syn::Error::new(arg.span, "error");
+ Err(e).expect_or_abort("Result::expect_or_abort() test")
+ }
+
+ "result_unwrap" => {
+ let e = syn::Error::new(arg.span, "Result::unwrap_or_abort() test");
+ Err(e).unwrap_or_abort()
+ }
+
+ "option_expect" => None.expect_or_abort("Option::expect_or_abort() test"),
+
+ "need_default" => {
+ set_dummy(quote! {
+ impl Default for NeedDefault {
+ fn default() -> Self {
+ NeedDefault::A
+ }
+ }
+ });
+
+ abort!(arg.span, "set_dummy test")
+ }
+
+ part if part.starts_with("multi") => {
+ let no_help: Option<String> = Option::None;
+ let help = Some("Option help test");
+ emit_error!(
+ arg.span,
+ "multiple error part: {}", part;
+ note = "help {} test", "message";
+ hint =? help;
+ wow = "I see what you did here...";
+ help =? no_help
+ )
+ }
+
+ _ => name.push_str(&arg.part),
+ }
+ }
+
+ // test that unrelated panics are not affected
+ if name.is_empty() {
+ panic!("unrelated panic test")
+ }
+
+ let name = Ident::new(&name, Span::call_site());
+ quote!( fn #name() {} ).into()
+}
diff --git a/proc-macro-error/test-crate/tests/macro-errors.rs b/proc-macro-error/test-crate/tests/macro-errors.rs
new file mode 100644
index 0000000..8c672eb
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/macro-errors.rs
@@ -0,0 +1,6 @@
+#[rustversion::attr(any(not(stable), before(1.39)), ignore)]
+#[test]
+fn ui() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/*.rs");
+}
diff --git a/proc-macro-error/test-crate/tests/ok.rs b/proc-macro-error/test-crate/tests/ok.rs
new file mode 100644
index 0000000..9b6a3d1
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ok.rs
@@ -0,0 +1,9 @@
+extern crate test_crate;
+
+use test_crate::make_fn;
+
+make_fn!(it, _, works);
+
+fn main() {
+ it_works();
+}
diff --git a/proc-macro-error/test-crate/tests/ui/abort.rs b/proc-macro-error/test-crate/tests/ui/abort.rs
new file mode 100644
index 0000000..717d772
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/abort.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+make_fn!(abort);
+
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/abort.stderr b/proc-macro-error/test-crate/tests/ui/abort.stderr
new file mode 100644
index 0000000..7c4e6a0
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/abort.stderr
@@ -0,0 +1,8 @@
+error: abort! 3+ args test
+
+ = help: help message test
+
+ --> $DIR/abort.rs:4:10
+ |
+4 | make_fn!(abort);
+ | ^^^^^
diff --git a/proc-macro-error/test-crate/tests/ui/call_site.rs b/proc-macro-error/test-crate/tests/ui/call_site.rs
new file mode 100644
index 0000000..7184cc4
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/call_site.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+make_fn!(abort_call_site);
+
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/call_site.stderr b/proc-macro-error/test-crate/tests/ui/call_site.stderr
new file mode 100644
index 0000000..d630a3a
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/call_site.stderr
@@ -0,0 +1,8 @@
+error: abort_call_site! 2+ args test
+
+ = help: help message test
+
+ --> $DIR/call_site.rs:4:1
+ |
+4 | make_fn!(abort_call_site);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
diff --git a/proc-macro-error/test-crate/tests/ui/direct_abort.rs b/proc-macro-error/test-crate/tests/ui/direct_abort.rs
new file mode 100644
index 0000000..b5a4c97
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/direct_abort.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+make_fn!(direct_abort);
+
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/direct_abort.stderr b/proc-macro-error/test-crate/tests/ui/direct_abort.stderr
new file mode 100644
index 0000000..7cfbae8
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/direct_abort.stderr
@@ -0,0 +1,5 @@
+error: direct MacroError::abort() test
+ --> $DIR/direct_abort.rs:4:10
+ |
+4 | make_fn!(direct_abort);
+ | ^^^^^^^^^^^^
diff --git a/proc-macro-error/test-crate/tests/ui/dummy.rs b/proc-macro-error/test-crate/tests/ui/dummy.rs
new file mode 100644
index 0000000..7514fe0
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/dummy.rs
@@ -0,0 +1,16 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+enum NeedDefault {
+ A,
+ B
+}
+
+make_fn!(need_default);
+
+fn main() {
+ let _ = NeedDefault::default();
+}
+
+
+
diff --git a/proc-macro-error/test-crate/tests/ui/dummy.stderr b/proc-macro-error/test-crate/tests/ui/dummy.stderr
new file mode 100644
index 0000000..fd531be
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/dummy.stderr
@@ -0,0 +1,5 @@
+error: set_dummy test
+ --> $DIR/dummy.rs:9:10
+ |
+9 | make_fn!(need_default);
+ | ^^^^^^^^^^^^
diff --git a/proc-macro-error/test-crate/tests/ui/multi-error.rs b/proc-macro-error/test-crate/tests/ui/multi-error.rs
new file mode 100644
index 0000000..07fbb03
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/multi-error.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+make_fn!(multi1, multi2, _, multi3);
+
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/multi-error.stderr b/proc-macro-error/test-crate/tests/ui/multi-error.stderr
new file mode 100644
index 0000000..25174d5
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/multi-error.stderr
@@ -0,0 +1,32 @@
+error: multiple error part: multi1
+
+ = note: help message test
+ = help: Option help test
+ = note: I see what you did here...
+
+ --> $DIR/multi-error.rs:4:10
+ |
+4 | make_fn!(multi1, multi2, _, multi3);
+ | ^^^^^^
+
+error: multiple error part: multi2
+
+ = note: help message test
+ = help: Option help test
+ = note: I see what you did here...
+
+ --> $DIR/multi-error.rs:4:18
+ |
+4 | make_fn!(multi1, multi2, _, multi3);
+ | ^^^^^^
+
+error: multiple error part: multi3
+
+ = note: help message test
+ = help: Option help test
+ = note: I see what you did here...
+
+ --> $DIR/multi-error.rs:4:29
+ |
+4 | make_fn!(multi1, multi2, _, multi3);
+ | ^^^^^^
diff --git a/proc-macro-error/test-crate/tests/ui/not_proc_macro.rs b/proc-macro-error/test-crate/tests/ui/not_proc_macro.rs
new file mode 100644
index 0000000..e241c5c
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/not_proc_macro.rs
@@ -0,0 +1,4 @@
+use proc_macro_error::proc_macro_error;
+
+#[proc_macro_error]
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/not_proc_macro.stderr b/proc-macro-error/test-crate/tests/ui/not_proc_macro.stderr
new file mode 100644
index 0000000..52d6a09
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/not_proc_macro.stderr
@@ -0,0 +1,8 @@
+error: #[proc_macro_error] attribute can be used only with a proc-macro
+
+ hint: if you are really sure that #[proc_macro_error] should be applied to this exact function use #[proc_macro_error(allow_not_macro)]
+
+ --> $DIR/not_proc_macro.rs:3:1
+ |
+3 | #[proc_macro_error]
+ | ^^^^^^^^^^^^^^^^^^^
diff --git a/proc-macro-error/test-crate/tests/ui/option_expect.rs b/proc-macro-error/test-crate/tests/ui/option_expect.rs
new file mode 100644
index 0000000..20288ca
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/option_expect.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+make_fn!(option_expect);
+
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/option_expect.stderr b/proc-macro-error/test-crate/tests/ui/option_expect.stderr
new file mode 100644
index 0000000..dd9ecd8
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/option_expect.stderr
@@ -0,0 +1,5 @@
+error: Option::expect_or_abort() test
+ --> $DIR/option_expect.rs:4:1
+ |
+4 | make_fn!(option_expect);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
diff --git a/proc-macro-error/test-crate/tests/ui/result_expect.rs b/proc-macro-error/test-crate/tests/ui/result_expect.rs
new file mode 100644
index 0000000..a42740b
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/result_expect.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+make_fn!(result_expect);
+
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/result_expect.stderr b/proc-macro-error/test-crate/tests/ui/result_expect.stderr
new file mode 100644
index 0000000..c2dd81c
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/result_expect.stderr
@@ -0,0 +1,5 @@
+error: Result::expect_or_abort() test: error
+ --> $DIR/result_expect.rs:4:10
+ |
+4 | make_fn!(result_expect);
+ | ^^^^^^^^^^^^^
diff --git a/proc-macro-error/test-crate/tests/ui/result_unwrap.rs b/proc-macro-error/test-crate/tests/ui/result_unwrap.rs
new file mode 100644
index 0000000..9b7fb1c
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/result_unwrap.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+make_fn!(result_unwrap);
+
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/result_unwrap.stderr b/proc-macro-error/test-crate/tests/ui/result_unwrap.stderr
new file mode 100644
index 0000000..2e614bd
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/result_unwrap.stderr
@@ -0,0 +1,5 @@
+error: Result::unwrap_or_abort() test
+ --> $DIR/result_unwrap.rs:4:10
+ |
+4 | make_fn!(result_unwrap);
+ | ^^^^^^^^^^^^^
diff --git a/proc-macro-error/test-crate/tests/ui/unknown_setting.rs b/proc-macro-error/test-crate/tests/ui/unknown_setting.rs
new file mode 100644
index 0000000..d8e58ea
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/unknown_setting.rs
@@ -0,0 +1,4 @@
+use proc_macro_error::proc_macro_error;
+
+#[proc_macro_error(allow_not_macro, assert_unwind_safe, trololo)]
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/unknown_setting.stderr b/proc-macro-error/test-crate/tests/ui/unknown_setting.stderr
new file mode 100644
index 0000000..a55de0b
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/unknown_setting.stderr
@@ -0,0 +1,5 @@
+error: unknown setting `trololo`, expected one of `assert_unwind_safe`, `allow_not_macro`, `proc_macro_hack`
+ --> $DIR/unknown_setting.rs:3:57
+ |
+3 | #[proc_macro_error(allow_not_macro, assert_unwind_safe, trololo)]
+ | ^^^^^^^
diff --git a/proc-macro-error/test-crate/tests/ui/unrelated_panic.rs b/proc-macro-error/test-crate/tests/ui/unrelated_panic.rs
new file mode 100644
index 0000000..4863e5b
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/unrelated_panic.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::make_fn;
+
+make_fn!();
+
+fn main() {}
diff --git a/proc-macro-error/test-crate/tests/ui/unrelated_panic.stderr b/proc-macro-error/test-crate/tests/ui/unrelated_panic.stderr
new file mode 100644
index 0000000..b852cfd
--- /dev/null
+++ b/proc-macro-error/test-crate/tests/ui/unrelated_panic.stderr
@@ -0,0 +1,7 @@
+error: proc macro panicked
+ --> $DIR/unrelated_panic.rs:4:1
+ |
+4 | make_fn!();
+ | ^^^^^^^^^^^
+ |
+ = help: message: unrelated panic test
diff --git a/proc-macro2/.gitignore b/proc-macro2/.gitignore
new file mode 100644
index 0000000..6936990
--- /dev/null
+++ b/proc-macro2/.gitignore
@@ -0,0 +1,3 @@
+/target
+**/*.rs.bk
+Cargo.lock
diff --git a/proc-macro2/.travis.yml b/proc-macro2/.travis.yml
new file mode 100644
index 0000000..acddb57
--- /dev/null
+++ b/proc-macro2/.travis.yml
@@ -0,0 +1,36 @@
+language: rust
+sudo: false
+
+matrix:
+ include:
+ - rust: 1.31.0
+ - rust: stable
+ - rust: beta
+ - rust: nightly
+ script:
+ - cargo test
+ - cargo test --no-default-features
+ - cargo test --no-default-features -- --ignored # run the ignored test to make sure the `proc-macro` feature is disabled
+ - cargo test --features span-locations
+ - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test
+ - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features
+ - RUSTFLAGS='-Z allow-features=' cargo test
+ - cargo update -Z minimal-versions && cargo build
+ - rust: nightly
+ name: WebAssembly
+ install: rustup target add wasm32-unknown-unknown
+ script: cargo test --target wasm32-unknown-unknown --no-run
+
+before_script:
+ - set -o errexit
+
+script:
+ - cargo test
+ - cargo test --no-default-features
+ - cargo test --features span-locations
+ - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test
+ - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features
+
+notifications:
+ email:
+ on_success: never
diff --git a/proc-macro2/Cargo.toml b/proc-macro2/Cargo.toml
new file mode 100644
index 0000000..a7d0865
--- /dev/null
+++ b/proc-macro2/Cargo.toml
@@ -0,0 +1,57 @@
+[package]
+name = "proc-macro2"
+version = "1.0.7" # remember to update html_root_url
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+license = "MIT OR Apache-2.0"
+readme = "README.md"
+keywords = ["macros"]
+repository = "https://github.com/alexcrichton/proc-macro2"
+homepage = "https://github.com/alexcrichton/proc-macro2"
+documentation = "https://docs.rs/proc-macro2"
+edition = "2018"
+description = """
+A stable implementation of the upcoming new `proc_macro` API. Comes with an
+option, off by default, to also reimplement itself in terms of the upstream
+unstable API.
+"""
+
+[package.metadata.docs.rs]
+rustc-args = ["--cfg", "procmacro2_semver_exempt"]
+rustdoc-args = ["--cfg", "procmacro2_semver_exempt"]
+
+[dependencies]
+unicode-xid = "0.2"
+
+[dev-dependencies]
+quote = { version = "1.0", default_features = false }
+
+[features]
+proc-macro = []
+default = ["proc-macro"]
+
+# Expose methods Span::start and Span::end which give the line/column location
+# of a token.
+span-locations = []
+
+# This feature no longer means anything.
+nightly = []
+
+[badges]
+travis-ci = { repository = "alexcrichton/proc-macro2" }
+
+[workspace]
+members = ["benches/bench-libproc-macro"]
+
+[patch.crates-io]
+# Our doc tests depend on quote which depends on proc-macro2. Without this line,
+# the proc-macro2 dependency of quote would be the released version of
+# proc-macro2. Quote would implement its traits for types from that proc-macro2,
+# meaning impls would be missing when tested against types from the local
+# proc-macro2.
+#
+# Travis builds that are in progress at the time that you publish may spuriously
+# fail. This is because they'll be building a local proc-macro2 which carries
+# the second-most-recent version number, pulling in quote which resolves to a
+# dependency on the just-published most recent version number. Thus the patch
+# will fail to apply because the version numbers are different.
+proc-macro2 = { path = "." }
diff --git a/proc-macro2/LICENSE-APACHE b/proc-macro2/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/proc-macro2/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/proc-macro2/LICENSE-MIT b/proc-macro2/LICENSE-MIT
new file mode 100644
index 0000000..39e0ed6
--- /dev/null
+++ b/proc-macro2/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 Alex Crichton
+
+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/proc-macro2/README.md b/proc-macro2/README.md
new file mode 100644
index 0000000..19b0c3b
--- /dev/null
+++ b/proc-macro2/README.md
@@ -0,0 +1,93 @@
+# proc-macro2
+
+[![Build Status](https://api.travis-ci.com/alexcrichton/proc-macro2.svg?branch=master)](https://travis-ci.com/alexcrichton/proc-macro2)
+[![Latest Version](https://img.shields.io/crates/v/proc-macro2.svg)](https://crates.io/crates/proc-macro2)
+[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/proc-macro2)
+
+A wrapper around the procedural macro API of the compiler's `proc_macro` crate.
+This library serves two purposes:
+
+- **Bring proc-macro-like functionality to other contexts like build.rs and
+ main.rs.** Types from `proc_macro` are entirely specific to procedural macros
+ and cannot ever exist in code outside of a procedural macro. Meanwhile
+ `proc_macro2` types may exist anywhere including non-macro code. By developing
+ foundational libraries like [syn] and [quote] against `proc_macro2` rather
+ than `proc_macro`, the procedural macro ecosystem becomes easily applicable to
+ many other use cases and we avoid reimplementing non-macro equivalents of
+ those libraries.
+
+- **Make procedural macros unit testable.** As a consequence of being specific
+ to procedural macros, nothing that uses `proc_macro` can be executed from a
+ unit test. In order for helper libraries or components of a macro to be
+ testable in isolation, they must be implemented using `proc_macro2`.
+
+[syn]: https://github.com/dtolnay/syn
+[quote]: https://github.com/dtolnay/quote
+
+## Usage
+
+```toml
+[dependencies]
+proc-macro2 = "1.0"
+```
+
+The skeleton of a typical procedural macro typically looks like this:
+
+```rust
+extern crate proc_macro;
+
+#[proc_macro_derive(MyDerive)]
+pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let input = proc_macro2::TokenStream::from(input);
+
+ let output: proc_macro2::TokenStream = {
+ /* transform input */
+ };
+
+ proc_macro::TokenStream::from(output)
+}
+```
+
+If parsing with [Syn], you'll use [`parse_macro_input!`] instead to propagate
+parse errors correctly back to the compiler when parsing fails.
+
+[`parse_macro_input!`]: https://docs.rs/syn/1.0/syn/macro.parse_macro_input.html
+
+## Unstable features
+
+The default feature set of proc-macro2 tracks the most recent stable compiler
+API. Functionality in `proc_macro` that is not yet stable is not exposed by
+proc-macro2 by default.
+
+To opt into the additional APIs available in the most recent nightly compiler,
+the `procmacro2_semver_exempt` config flag must be passed to rustc. We will
+polyfill those nightly-only APIs back to Rust 1.31.0. As these are unstable APIs
+that track the nightly compiler, minor versions of proc-macro2 may make breaking
+changes to them at any time.
+
+```
+RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build
+```
+
+Note that this must not only be done for your crate, but for any crate that
+depends on your crate. This infectious nature is intentional, as it serves as a
+reminder that you are outside of the normal semver guarantees.
+
+Semver exempt methods are marked as such in the proc-macro2 documentation.
+
+<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/proc-macro2/benches/bench-libproc-macro/Cargo.toml b/proc-macro2/benches/bench-libproc-macro/Cargo.toml
new file mode 100644
index 0000000..41d106d
--- /dev/null
+++ b/proc-macro2/benches/bench-libproc-macro/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "bench-libproc-macro"
+version = "0.0.0"
+edition = "2018"
+publish = false
+
+[lib]
+path = "lib.rs"
+proc-macro = true
+
+[[bin]]
+name = "bench-libproc-macro"
+path = "main.rs"
diff --git a/proc-macro2/benches/bench-libproc-macro/README.md b/proc-macro2/benches/bench-libproc-macro/README.md
new file mode 100644
index 0000000..80e4939
--- /dev/null
+++ b/proc-macro2/benches/bench-libproc-macro/README.md
@@ -0,0 +1,10 @@
+Example output:
+
+```console
+$ cargo check --release
+
+ Compiling bench-libproc-macro v0.0.0
+STRING: 8 millis
+TOKENSTREAM: 25721 millis
+ Finished release [optimized] target(s) in 26.15s
+```
diff --git a/proc-macro2/benches/bench-libproc-macro/lib.rs b/proc-macro2/benches/bench-libproc-macro/lib.rs
new file mode 100644
index 0000000..46b3711
--- /dev/null
+++ b/proc-macro2/benches/bench-libproc-macro/lib.rs
@@ -0,0 +1,49 @@
+extern crate proc_macro;
+
+use proc_macro::{Ident, Punct, Spacing, Span, TokenStream, TokenTree};
+use std::iter::once;
+use std::time::Instant;
+
+const N: u32 = 7000;
+
+#[proc_macro]
+pub fn bench(_input: TokenStream) -> TokenStream {
+ let start = Instant::now();
+ let mut string = String::new();
+ for _ in 0..N {
+ string += "core";
+ string += ":";
+ string += ":";
+ string += "option";
+ string += ":";
+ string += ":";
+ string += "Option";
+ string += ":";
+ string += ":";
+ string += "None";
+ string += ",";
+ }
+ string.parse::<TokenStream>().unwrap();
+ eprintln!("STRING: {} millis", start.elapsed().as_millis());
+
+ let start = Instant::now();
+ let span = Span::call_site();
+ let mut tokens = TokenStream::new();
+ for _ in 0..N {
+ // Similar to what is emitted by quote.
+ tokens.extend(once(TokenTree::Ident(Ident::new("core", span))));
+ tokens.extend(once(TokenTree::Punct(Punct::new(':', Spacing::Joint))));
+ tokens.extend(once(TokenTree::Punct(Punct::new(':', Spacing::Alone))));
+ tokens.extend(once(TokenTree::Ident(Ident::new("option", span))));
+ tokens.extend(once(TokenTree::Punct(Punct::new(':', Spacing::Joint))));
+ tokens.extend(once(TokenTree::Punct(Punct::new(':', Spacing::Alone))));
+ tokens.extend(once(TokenTree::Ident(Ident::new("Option", span))));
+ tokens.extend(once(TokenTree::Punct(Punct::new(':', Spacing::Joint))));
+ tokens.extend(once(TokenTree::Punct(Punct::new(':', Spacing::Alone))));
+ tokens.extend(once(TokenTree::Ident(Ident::new("None", span))));
+ tokens.extend(once(TokenTree::Punct(Punct::new(',', Spacing::Joint))));
+ }
+ eprintln!("TOKENSTREAM: {} millis", start.elapsed().as_millis());
+
+ TokenStream::new()
+}
diff --git a/proc-macro2/benches/bench-libproc-macro/main.rs b/proc-macro2/benches/bench-libproc-macro/main.rs
new file mode 100644
index 0000000..34eedf6
--- /dev/null
+++ b/proc-macro2/benches/bench-libproc-macro/main.rs
@@ -0,0 +1,3 @@
+bench_libproc_macro::bench!();
+
+fn main() {}
diff --git a/proc-macro2/build.rs b/proc-macro2/build.rs
new file mode 100644
index 0000000..deb9b92
--- /dev/null
+++ b/proc-macro2/build.rs
@@ -0,0 +1,129 @@
+// rustc-cfg emitted by the build script:
+//
+// "use_proc_macro"
+// Link to extern crate proc_macro. Available on any compiler and any target
+// except wasm32. Requires "proc-macro" Cargo cfg to be enabled (default is
+// enabled). On wasm32 we never link to proc_macro even if "proc-macro" cfg
+// is enabled.
+//
+// "wrap_proc_macro"
+// Wrap types from libproc_macro rather than polyfilling the whole API.
+// Enabled on rustc 1.29+ as long as procmacro2_semver_exempt is not set,
+// because we can't emulate the unstable API without emulating everything
+// else. Also enabled unconditionally on nightly, in which case the
+// procmacro2_semver_exempt surface area is implemented by using the
+// nightly-only proc_macro API.
+//
+// "proc_macro_span"
+// Enable non-dummy behavior of Span::start and Span::end methods which
+// requires an unstable compiler feature. Enabled when building with
+// nightly, unless `-Z allow-feature` in RUSTFLAGS disallows unstable
+// features.
+//
+// "super_unstable"
+// Implement the semver exempt API in terms of the nightly-only proc_macro
+// API. Enabled when using procmacro2_semver_exempt on a nightly compiler.
+//
+// "span_locations"
+// Provide methods Span::start and Span::end which give the line/column
+// location of a token. Enabled by procmacro2_semver_exempt or the
+// "span-locations" Cargo cfg. This is behind a cfg because tracking
+// location inside spans is a performance hit.
+
+use std::env;
+use std::process::{self, Command};
+use std::str;
+
+fn main() {
+ println!("cargo:rerun-if-changed=build.rs");
+
+ let version = match rustc_version() {
+ Some(version) => version,
+ None => return,
+ };
+
+ if version.minor < 31 {
+ eprintln!("Minimum supported rustc version is 1.31");
+ process::exit(1);
+ }
+
+ let semver_exempt = cfg!(procmacro2_semver_exempt);
+ if semver_exempt {
+ // https://github.com/alexcrichton/proc-macro2/issues/147
+ println!("cargo:rustc-cfg=procmacro2_semver_exempt");
+ }
+
+ if semver_exempt || cfg!(feature = "span-locations") {
+ println!("cargo:rustc-cfg=span_locations");
+ }
+
+ let target = env::var("TARGET").unwrap();
+ if !enable_use_proc_macro(&target) {
+ return;
+ }
+
+ println!("cargo:rustc-cfg=use_proc_macro");
+
+ if version.nightly || !semver_exempt {
+ println!("cargo:rustc-cfg=wrap_proc_macro");
+ }
+
+ if version.nightly && feature_allowed("proc_macro_span") {
+ println!("cargo:rustc-cfg=proc_macro_span");
+ }
+
+ if semver_exempt && version.nightly {
+ println!("cargo:rustc-cfg=super_unstable");
+ }
+}
+
+fn enable_use_proc_macro(target: &str) -> bool {
+ // wasm targets don't have the `proc_macro` crate, disable this feature.
+ if target.contains("wasm32") {
+ return false;
+ }
+
+ // Otherwise, only enable it if our feature is actually enabled.
+ cfg!(feature = "proc-macro")
+}
+
+struct RustcVersion {
+ minor: u32,
+ nightly: bool,
+}
+
+fn rustc_version() -> Option<RustcVersion> {
+ let rustc = env::var_os("RUSTC")?;
+ let output = Command::new(rustc).arg("--version").output().ok()?;
+ let version = str::from_utf8(&output.stdout).ok()?;
+ let nightly = version.contains("nightly") || version.contains("dev");
+ let mut pieces = version.split('.');
+ if pieces.next() != Some("rustc 1") {
+ return None;
+ }
+ let minor = pieces.next()?.parse().ok()?;
+ Some(RustcVersion { minor, nightly })
+}
+
+fn feature_allowed(feature: &str) -> bool {
+ // Recognized formats:
+ //
+ // -Z allow-features=feature1,feature2
+ //
+ // -Zallow-features=feature1,feature2
+
+ if let Some(rustflags) = env::var_os("RUSTFLAGS") {
+ for mut flag in rustflags.to_string_lossy().split(' ') {
+ if flag.starts_with("-Z") {
+ flag = &flag["-Z".len()..];
+ }
+ if flag.starts_with("allow-features=") {
+ flag = &flag["allow-features=".len()..];
+ return flag.split(',').any(|allowed| allowed == feature);
+ }
+ }
+ }
+
+ // No allow-features= flag, allowed by default.
+ true
+}
diff --git a/proc-macro2/src/fallback.rs b/proc-macro2/src/fallback.rs
new file mode 100644
index 0000000..9762d3b
--- /dev/null
+++ b/proc-macro2/src/fallback.rs
@@ -0,0 +1,1458 @@
+#[cfg(span_locations)]
+use std::cell::RefCell;
+#[cfg(span_locations)]
+use std::cmp;
+use std::fmt;
+use std::iter;
+use std::ops::RangeBounds;
+#[cfg(procmacro2_semver_exempt)]
+use std::path::Path;
+use std::path::PathBuf;
+use std::str::FromStr;
+use std::vec;
+
+use crate::strnom::{block_comment, skip_whitespace, whitespace, word_break, Cursor, PResult};
+use crate::{Delimiter, Punct, Spacing, TokenTree};
+use unicode_xid::UnicodeXID;
+
+#[derive(Clone)]
+pub struct TokenStream {
+ inner: Vec<TokenTree>,
+}
+
+#[derive(Debug)]
+pub struct LexError;
+
+impl TokenStream {
+ pub fn new() -> TokenStream {
+ TokenStream { inner: Vec::new() }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.inner.len() == 0
+ }
+}
+
+#[cfg(span_locations)]
+fn get_cursor(src: &str) -> Cursor {
+ // Create a dummy file & add it to the source map
+ SOURCE_MAP.with(|cm| {
+ let mut cm = cm.borrow_mut();
+ let name = format!("<parsed string {}>", cm.files.len());
+ let span = cm.add_file(&name, src);
+ Cursor {
+ rest: src,
+ off: span.lo,
+ }
+ })
+}
+
+#[cfg(not(span_locations))]
+fn get_cursor(src: &str) -> Cursor {
+ Cursor { rest: src }
+}
+
+impl FromStr for TokenStream {
+ type Err = LexError;
+
+ fn from_str(src: &str) -> Result<TokenStream, LexError> {
+ // Create a dummy file & add it to the source map
+ let cursor = get_cursor(src);
+
+ match token_stream(cursor) {
+ Ok((input, output)) => {
+ if skip_whitespace(input).len() != 0 {
+ Err(LexError)
+ } else {
+ Ok(output)
+ }
+ }
+ Err(LexError) => Err(LexError),
+ }
+ }
+}
+
+impl fmt::Display for TokenStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut joint = false;
+ for (i, tt) in self.inner.iter().enumerate() {
+ if i != 0 && !joint {
+ write!(f, " ")?;
+ }
+ joint = false;
+ match *tt {
+ TokenTree::Group(ref tt) => {
+ let (start, end) = match tt.delimiter() {
+ Delimiter::Parenthesis => ("(", ")"),
+ Delimiter::Brace => ("{", "}"),
+ Delimiter::Bracket => ("[", "]"),
+ Delimiter::None => ("", ""),
+ };
+ if tt.stream().into_iter().next().is_none() {
+ write!(f, "{} {}", start, end)?
+ } else {
+ write!(f, "{} {} {}", start, tt.stream(), end)?
+ }
+ }
+ TokenTree::Ident(ref tt) => write!(f, "{}", tt)?,
+ TokenTree::Punct(ref tt) => {
+ write!(f, "{}", tt.as_char())?;
+ match tt.spacing() {
+ Spacing::Alone => {}
+ Spacing::Joint => joint = true,
+ }
+ }
+ TokenTree::Literal(ref tt) => write!(f, "{}", tt)?,
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl fmt::Debug for TokenStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("TokenStream ")?;
+ f.debug_list().entries(self.clone()).finish()
+ }
+}
+
+#[cfg(use_proc_macro)]
+impl From<proc_macro::TokenStream> for TokenStream {
+ fn from(inner: proc_macro::TokenStream) -> TokenStream {
+ inner
+ .to_string()
+ .parse()
+ .expect("compiler token stream parse failed")
+ }
+}
+
+#[cfg(use_proc_macro)]
+impl From<TokenStream> for proc_macro::TokenStream {
+ fn from(inner: TokenStream) -> proc_macro::TokenStream {
+ inner
+ .to_string()
+ .parse()
+ .expect("failed to parse to compiler tokens")
+ }
+}
+
+impl From<TokenTree> for TokenStream {
+ fn from(tree: TokenTree) -> TokenStream {
+ TokenStream { inner: vec![tree] }
+ }
+}
+
+impl iter::FromIterator<TokenTree> for TokenStream {
+ fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
+ let mut v = Vec::new();
+
+ for token in streams.into_iter() {
+ v.push(token);
+ }
+
+ TokenStream { inner: v }
+ }
+}
+
+impl iter::FromIterator<TokenStream> for TokenStream {
+ fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
+ let mut v = Vec::new();
+
+ for stream in streams.into_iter() {
+ v.extend(stream.inner);
+ }
+
+ TokenStream { inner: v }
+ }
+}
+
+impl Extend<TokenTree> for TokenStream {
+ fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) {
+ self.inner.extend(streams);
+ }
+}
+
+impl Extend<TokenStream> for TokenStream {
+ fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
+ self.inner
+ .extend(streams.into_iter().flat_map(|stream| stream));
+ }
+}
+
+pub type TokenTreeIter = vec::IntoIter<TokenTree>;
+
+impl IntoIterator for TokenStream {
+ type Item = TokenTree;
+ type IntoIter = TokenTreeIter;
+
+ fn into_iter(self) -> TokenTreeIter {
+ self.inner.into_iter()
+ }
+}
+
+#[derive(Clone, PartialEq, Eq)]
+pub struct SourceFile {
+ path: PathBuf,
+}
+
+impl SourceFile {
+ /// Get the path to this source file as a string.
+ pub fn path(&self) -> PathBuf {
+ self.path.clone()
+ }
+
+ pub fn is_real(&self) -> bool {
+ // XXX(nika): Support real files in the future?
+ false
+ }
+}
+
+impl fmt::Debug for SourceFile {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("SourceFile")
+ .field("path", &self.path())
+ .field("is_real", &self.is_real())
+ .finish()
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct LineColumn {
+ pub line: usize,
+ pub column: usize,
+}
+
+#[cfg(span_locations)]
+thread_local! {
+ static SOURCE_MAP: RefCell<SourceMap> = RefCell::new(SourceMap {
+ // NOTE: We start with a single dummy file which all call_site() and
+ // def_site() spans reference.
+ files: vec![{
+ #[cfg(procmacro2_semver_exempt)]
+ {
+ FileInfo {
+ name: "<unspecified>".to_owned(),
+ span: Span { lo: 0, hi: 0 },
+ lines: vec![0],
+ }
+ }
+
+ #[cfg(not(procmacro2_semver_exempt))]
+ {
+ FileInfo {
+ span: Span { lo: 0, hi: 0 },
+ lines: vec![0],
+ }
+ }
+ }],
+ });
+}
+
+#[cfg(span_locations)]
+struct FileInfo {
+ #[cfg(procmacro2_semver_exempt)]
+ name: String,
+ span: Span,
+ lines: Vec<usize>,
+}
+
+#[cfg(span_locations)]
+impl FileInfo {
+ fn offset_line_column(&self, offset: usize) -> LineColumn {
+ assert!(self.span_within(Span {
+ lo: offset as u32,
+ hi: offset as u32
+ }));
+ let offset = offset - self.span.lo as usize;
+ match self.lines.binary_search(&offset) {
+ Ok(found) => LineColumn {
+ line: found + 1,
+ column: 0,
+ },
+ Err(idx) => LineColumn {
+ line: idx,
+ column: offset - self.lines[idx - 1],
+ },
+ }
+ }
+
+ fn span_within(&self, span: Span) -> bool {
+ span.lo >= self.span.lo && span.hi <= self.span.hi
+ }
+}
+
+/// Computesthe offsets of each line in the given source string.
+#[cfg(span_locations)]
+fn lines_offsets(s: &str) -> Vec<usize> {
+ let mut lines = vec![0];
+ let mut prev = 0;
+ while let Some(len) = s[prev..].find('\n') {
+ prev += len + 1;
+ lines.push(prev);
+ }
+ lines
+}
+
+#[cfg(span_locations)]
+struct SourceMap {
+ files: Vec<FileInfo>,
+}
+
+#[cfg(span_locations)]
+impl SourceMap {
+ fn next_start_pos(&self) -> u32 {
+ // Add 1 so there's always space between files.
+ //
+ // We'll always have at least 1 file, as we initialize our files list
+ // with a dummy file.
+ self.files.last().unwrap().span.hi + 1
+ }
+
+ fn add_file(&mut self, name: &str, src: &str) -> Span {
+ let lines = lines_offsets(src);
+ let lo = self.next_start_pos();
+ // XXX(nika): Shouild we bother doing a checked cast or checked add here?
+ let span = Span {
+ lo,
+ hi: lo + (src.len() as u32),
+ };
+
+ #[cfg(procmacro2_semver_exempt)]
+ self.files.push(FileInfo {
+ name: name.to_owned(),
+ span,
+ lines,
+ });
+
+ #[cfg(not(procmacro2_semver_exempt))]
+ self.files.push(FileInfo { span, lines });
+ let _ = name;
+
+ span
+ }
+
+ fn fileinfo(&self, span: Span) -> &FileInfo {
+ for file in &self.files {
+ if file.span_within(span) {
+ return file;
+ }
+ }
+ panic!("Invalid span with no related FileInfo!");
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Span {
+ #[cfg(span_locations)]
+ lo: u32,
+ #[cfg(span_locations)]
+ hi: u32,
+}
+
+impl Span {
+ #[cfg(not(span_locations))]
+ pub fn call_site() -> Span {
+ Span {}
+ }
+
+ #[cfg(span_locations)]
+ pub fn call_site() -> Span {
+ Span { lo: 0, hi: 0 }
+ }
+
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn def_site() -> Span {
+ Span::call_site()
+ }
+
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn resolved_at(&self, _other: Span) -> Span {
+ // Stable spans consist only of line/column information, so
+ // `resolved_at` and `located_at` only select which span the
+ // caller wants line/column information from.
+ *self
+ }
+
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn located_at(&self, other: Span) -> Span {
+ other
+ }
+
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn source_file(&self) -> SourceFile {
+ SOURCE_MAP.with(|cm| {
+ let cm = cm.borrow();
+ let fi = cm.fileinfo(*self);
+ SourceFile {
+ path: Path::new(&fi.name).to_owned(),
+ }
+ })
+ }
+
+ #[cfg(span_locations)]
+ pub fn start(&self) -> LineColumn {
+ SOURCE_MAP.with(|cm| {
+ let cm = cm.borrow();
+ let fi = cm.fileinfo(*self);
+ fi.offset_line_column(self.lo as usize)
+ })
+ }
+
+ #[cfg(span_locations)]
+ pub fn end(&self) -> LineColumn {
+ SOURCE_MAP.with(|cm| {
+ let cm = cm.borrow();
+ let fi = cm.fileinfo(*self);
+ fi.offset_line_column(self.hi as usize)
+ })
+ }
+
+ #[cfg(not(span_locations))]
+ pub fn join(&self, _other: Span) -> Option<Span> {
+ Some(Span {})
+ }
+
+ #[cfg(span_locations)]
+ pub fn join(&self, other: Span) -> Option<Span> {
+ SOURCE_MAP.with(|cm| {
+ let cm = cm.borrow();
+ // If `other` is not within the same FileInfo as us, return None.
+ if !cm.fileinfo(*self).span_within(other) {
+ return None;
+ }
+ Some(Span {
+ lo: cmp::min(self.lo, other.lo),
+ hi: cmp::max(self.hi, other.hi),
+ })
+ })
+ }
+
+ #[cfg(not(span_locations))]
+ fn first_byte(self) -> Self {
+ self
+ }
+
+ #[cfg(span_locations)]
+ fn first_byte(self) -> Self {
+ Span {
+ lo: self.lo,
+ hi: cmp::min(self.lo.saturating_add(1), self.hi),
+ }
+ }
+
+ #[cfg(not(span_locations))]
+ fn last_byte(self) -> Self {
+ self
+ }
+
+ #[cfg(span_locations)]
+ fn last_byte(self) -> Self {
+ Span {
+ lo: cmp::max(self.hi.saturating_sub(1), self.lo),
+ hi: self.hi,
+ }
+ }
+}
+
+impl fmt::Debug for Span {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ #[cfg(procmacro2_semver_exempt)]
+ return write!(f, "bytes({}..{})", self.lo, self.hi);
+
+ #[cfg(not(procmacro2_semver_exempt))]
+ write!(f, "Span")
+ }
+}
+
+pub fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) {
+ if cfg!(procmacro2_semver_exempt) {
+ debug.field("span", &span);
+ }
+}
+
+#[derive(Clone)]
+pub struct Group {
+ delimiter: Delimiter,
+ stream: TokenStream,
+ span: Span,
+}
+
+impl Group {
+ pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
+ Group {
+ delimiter,
+ stream,
+ span: Span::call_site(),
+ }
+ }
+
+ pub fn delimiter(&self) -> Delimiter {
+ self.delimiter
+ }
+
+ pub fn stream(&self) -> TokenStream {
+ self.stream.clone()
+ }
+
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ pub fn span_open(&self) -> Span {
+ self.span.first_byte()
+ }
+
+ pub fn span_close(&self) -> Span {
+ self.span.last_byte()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.span = span;
+ }
+}
+
+impl fmt::Display for Group {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let (left, right) = match self.delimiter {
+ Delimiter::Parenthesis => ("(", ")"),
+ Delimiter::Brace => ("{", "}"),
+ Delimiter::Bracket => ("[", "]"),
+ Delimiter::None => ("", ""),
+ };
+
+ f.write_str(left)?;
+ self.stream.fmt(f)?;
+ f.write_str(right)?;
+
+ Ok(())
+ }
+}
+
+impl fmt::Debug for Group {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut debug = fmt.debug_struct("Group");
+ debug.field("delimiter", &self.delimiter);
+ debug.field("stream", &self.stream);
+ #[cfg(procmacro2_semver_exempt)]
+ debug.field("span", &self.span);
+ debug.finish()
+ }
+}
+
+#[derive(Clone)]
+pub struct Ident {
+ sym: String,
+ span: Span,
+ raw: bool,
+}
+
+impl Ident {
+ fn _new(string: &str, raw: bool, span: Span) -> Ident {
+ validate_ident(string);
+
+ Ident {
+ sym: string.to_owned(),
+ span,
+ raw,
+ }
+ }
+
+ pub fn new(string: &str, span: Span) -> Ident {
+ Ident::_new(string, false, span)
+ }
+
+ pub fn new_raw(string: &str, span: Span) -> Ident {
+ Ident::_new(string, true, span)
+ }
+
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.span = span;
+ }
+}
+
+fn is_ident_start(c: char) -> bool {
+ ('a' <= c && c <= 'z')
+ || ('A' <= c && c <= 'Z')
+ || c == '_'
+ || (c > '\x7f' && UnicodeXID::is_xid_start(c))
+}
+
+fn is_ident_continue(c: char) -> bool {
+ ('a' <= c && c <= 'z')
+ || ('A' <= c && c <= 'Z')
+ || c == '_'
+ || ('0' <= c && c <= '9')
+ || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
+}
+
+fn validate_ident(string: &str) {
+ let validate = string;
+ if validate.is_empty() {
+ panic!("Ident is not allowed to be empty; use Option<Ident>");
+ }
+
+ if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') {
+ panic!("Ident cannot be a number; use Literal instead");
+ }
+
+ fn ident_ok(string: &str) -> bool {
+ let mut chars = string.chars();
+ let first = chars.next().unwrap();
+ if !is_ident_start(first) {
+ return false;
+ }
+ for ch in chars {
+ if !is_ident_continue(ch) {
+ return false;
+ }
+ }
+ true
+ }
+
+ if !ident_ok(validate) {
+ panic!("{:?} is not a valid Ident", string);
+ }
+}
+
+impl PartialEq for Ident {
+ fn eq(&self, other: &Ident) -> bool {
+ self.sym == other.sym && self.raw == other.raw
+ }
+}
+
+impl<T> PartialEq<T> for Ident
+where
+ T: ?Sized + AsRef<str>,
+{
+ fn eq(&self, other: &T) -> bool {
+ let other = other.as_ref();
+ if self.raw {
+ other.starts_with("r#") && self.sym == other[2..]
+ } else {
+ self.sym == other
+ }
+ }
+}
+
+impl fmt::Display for Ident {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.raw {
+ "r#".fmt(f)?;
+ }
+ self.sym.fmt(f)
+ }
+}
+
+impl fmt::Debug for Ident {
+ // Ident(proc_macro), Ident(r#union)
+ #[cfg(not(procmacro2_semver_exempt))]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut debug = f.debug_tuple("Ident");
+ debug.field(&format_args!("{}", self));
+ debug.finish()
+ }
+
+ // Ident {
+ // sym: proc_macro,
+ // span: bytes(128..138)
+ // }
+ #[cfg(procmacro2_semver_exempt)]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut debug = f.debug_struct("Ident");
+ debug.field("sym", &format_args!("{}", self));
+ debug.field("span", &self.span);
+ debug.finish()
+ }
+}
+
+#[derive(Clone)]
+pub struct Literal {
+ text: String,
+ span: Span,
+}
+
+macro_rules! suffixed_numbers {
+ ($($name:ident => $kind:ident,)*) => ($(
+ pub fn $name(n: $kind) -> Literal {
+ Literal::_new(format!(concat!("{}", stringify!($kind)), n))
+ }
+ )*)
+}
+
+macro_rules! unsuffixed_numbers {
+ ($($name:ident => $kind:ident,)*) => ($(
+ pub fn $name(n: $kind) -> Literal {
+ Literal::_new(n.to_string())
+ }
+ )*)
+}
+
+impl Literal {
+ fn _new(text: String) -> Literal {
+ Literal {
+ text,
+ span: Span::call_site(),
+ }
+ }
+
+ suffixed_numbers! {
+ u8_suffixed => u8,
+ u16_suffixed => u16,
+ u32_suffixed => u32,
+ u64_suffixed => u64,
+ u128_suffixed => u128,
+ usize_suffixed => usize,
+ i8_suffixed => i8,
+ i16_suffixed => i16,
+ i32_suffixed => i32,
+ i64_suffixed => i64,
+ i128_suffixed => i128,
+ isize_suffixed => isize,
+
+ f32_suffixed => f32,
+ f64_suffixed => f64,
+ }
+
+ unsuffixed_numbers! {
+ u8_unsuffixed => u8,
+ u16_unsuffixed => u16,
+ u32_unsuffixed => u32,
+ u64_unsuffixed => u64,
+ u128_unsuffixed => u128,
+ usize_unsuffixed => usize,
+ i8_unsuffixed => i8,
+ i16_unsuffixed => i16,
+ i32_unsuffixed => i32,
+ i64_unsuffixed => i64,
+ i128_unsuffixed => i128,
+ isize_unsuffixed => isize,
+ }
+
+ pub fn f32_unsuffixed(f: f32) -> Literal {
+ let mut s = f.to_string();
+ if !s.contains(".") {
+ s.push_str(".0");
+ }
+ Literal::_new(s)
+ }
+
+ pub fn f64_unsuffixed(f: f64) -> Literal {
+ let mut s = f.to_string();
+ if !s.contains(".") {
+ s.push_str(".0");
+ }
+ Literal::_new(s)
+ }
+
+ pub fn string(t: &str) -> Literal {
+ let mut text = String::with_capacity(t.len() + 2);
+ text.push('"');
+ for c in t.chars() {
+ if c == '\'' {
+ // escape_default turns this into "\'" which is unnecessary.
+ text.push(c);
+ } else {
+ text.extend(c.escape_default());
+ }
+ }
+ text.push('"');
+ Literal::_new(text)
+ }
+
+ pub fn character(t: char) -> Literal {
+ let mut text = String::new();
+ text.push('\'');
+ if t == '"' {
+ // escape_default turns this into '\"' which is unnecessary.
+ text.push(t);
+ } else {
+ text.extend(t.escape_default());
+ }
+ text.push('\'');
+ Literal::_new(text)
+ }
+
+ pub fn byte_string(bytes: &[u8]) -> Literal {
+ let mut escaped = "b\"".to_string();
+ for b in bytes {
+ match *b {
+ b'\0' => escaped.push_str(r"\0"),
+ b'\t' => escaped.push_str(r"\t"),
+ b'\n' => escaped.push_str(r"\n"),
+ b'\r' => escaped.push_str(r"\r"),
+ b'"' => escaped.push_str("\\\""),
+ b'\\' => escaped.push_str("\\\\"),
+ b'\x20'..=b'\x7E' => escaped.push(*b as char),
+ _ => escaped.push_str(&format!("\\x{:02X}", b)),
+ }
+ }
+ escaped.push('"');
+ Literal::_new(escaped)
+ }
+
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.span = span;
+ }
+
+ pub fn subspan<R: RangeBounds<usize>>(&self, _range: R) -> Option<Span> {
+ None
+ }
+}
+
+impl fmt::Display for Literal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.text.fmt(f)
+ }
+}
+
+impl fmt::Debug for Literal {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut debug = fmt.debug_struct("Literal");
+ debug.field("lit", &format_args!("{}", self.text));
+ #[cfg(procmacro2_semver_exempt)]
+ debug.field("span", &self.span);
+ debug.finish()
+ }
+}
+
+fn token_stream(mut input: Cursor) -> PResult<TokenStream> {
+ let mut trees = Vec::new();
+ loop {
+ let input_no_ws = skip_whitespace(input);
+ if input_no_ws.rest.len() == 0 {
+ break;
+ }
+ if let Ok((a, tokens)) = doc_comment(input_no_ws) {
+ input = a;
+ trees.extend(tokens);
+ continue;
+ }
+
+ let (a, tt) = match token_tree(input_no_ws) {
+ Ok(p) => p,
+ Err(_) => break,
+ };
+ trees.push(tt);
+ input = a;
+ }
+ Ok((input, TokenStream { inner: trees }))
+}
+
+#[cfg(not(span_locations))]
+fn spanned<'a, T>(
+ input: Cursor<'a>,
+ f: fn(Cursor<'a>) -> PResult<'a, T>,
+) -> PResult<'a, (T, crate::Span)> {
+ let (a, b) = f(skip_whitespace(input))?;
+ Ok((a, ((b, crate::Span::_new_stable(Span::call_site())))))
+}
+
+#[cfg(span_locations)]
+fn spanned<'a, T>(
+ input: Cursor<'a>,
+ f: fn(Cursor<'a>) -> PResult<'a, T>,
+) -> PResult<'a, (T, crate::Span)> {
+ let input = skip_whitespace(input);
+ let lo = input.off;
+ let (a, b) = f(input)?;
+ let hi = a.off;
+ let span = crate::Span::_new_stable(Span { lo, hi });
+ Ok((a, (b, span)))
+}
+
+fn token_tree(input: Cursor) -> PResult<TokenTree> {
+ let (rest, (mut tt, span)) = spanned(input, token_kind)?;
+ tt.set_span(span);
+ Ok((rest, tt))
+}
+
+named!(token_kind -> TokenTree, alt!(
+ map!(group, |g| TokenTree::Group(crate::Group::_new_stable(g)))
+ |
+ map!(literal, |l| TokenTree::Literal(crate::Literal::_new_stable(l))) // must be before symbol
+ |
+ map!(op, TokenTree::Punct)
+ |
+ symbol_leading_ws
+));
+
+named!(group -> Group, alt!(
+ delimited!(
+ punct!("("),
+ token_stream,
+ punct!(")")
+ ) => { |ts| Group::new(Delimiter::Parenthesis, ts) }
+ |
+ delimited!(
+ punct!("["),
+ token_stream,
+ punct!("]")
+ ) => { |ts| Group::new(Delimiter::Bracket, ts) }
+ |
+ delimited!(
+ punct!("{"),
+ token_stream,
+ punct!("}")
+ ) => { |ts| Group::new(Delimiter::Brace, ts) }
+));
+
+fn symbol_leading_ws(input: Cursor) -> PResult<TokenTree> {
+ symbol(skip_whitespace(input))
+}
+
+fn symbol(input: Cursor) -> PResult<TokenTree> {
+ let raw = input.starts_with("r#");
+ let rest = input.advance((raw as usize) << 1);
+
+ let (rest, sym) = symbol_not_raw(rest)?;
+
+ if !raw {
+ let ident = crate::Ident::new(sym, crate::Span::call_site());
+ return Ok((rest, ident.into()));
+ }
+
+ if sym == "_" {
+ return Err(LexError);
+ }
+
+ let ident = crate::Ident::_new_raw(sym, crate::Span::call_site());
+ Ok((rest, ident.into()))
+}
+
+fn symbol_not_raw(input: Cursor) -> PResult<&str> {
+ let mut chars = input.char_indices();
+
+ match chars.next() {
+ Some((_, ch)) if is_ident_start(ch) => {}
+ _ => return Err(LexError),
+ }
+
+ let mut end = input.len();
+ for (i, ch) in chars {
+ if !is_ident_continue(ch) {
+ end = i;
+ break;
+ }
+ }
+
+ Ok((input.advance(end), &input.rest[..end]))
+}
+
+fn literal(input: Cursor) -> PResult<Literal> {
+ let input_no_ws = skip_whitespace(input);
+
+ match literal_nocapture(input_no_ws) {
+ Ok((a, ())) => {
+ let start = input.len() - input_no_ws.len();
+ let len = input_no_ws.len() - a.len();
+ let end = start + len;
+ Ok((a, Literal::_new(input.rest[start..end].to_string())))
+ }
+ Err(LexError) => Err(LexError),
+ }
+}
+
+named!(literal_nocapture -> (), alt!(
+ string
+ |
+ byte_string
+ |
+ byte
+ |
+ character
+ |
+ float
+ |
+ int
+));
+
+named!(string -> (), alt!(
+ quoted_string
+ |
+ preceded!(
+ punct!("r"),
+ raw_string
+ ) => { |_| () }
+));
+
+named!(quoted_string -> (), do_parse!(
+ punct!("\"") >>
+ cooked_string >>
+ tag!("\"") >>
+ option!(symbol_not_raw) >>
+ (())
+));
+
+fn cooked_string(input: Cursor) -> PResult<()> {
+ let mut chars = input.char_indices().peekable();
+ while let Some((byte_offset, ch)) = chars.next() {
+ match ch {
+ '"' => {
+ return Ok((input.advance(byte_offset), ()));
+ }
+ '\r' => {
+ if let Some((_, '\n')) = chars.next() {
+ // ...
+ } else {
+ break;
+ }
+ }
+ '\\' => match chars.next() {
+ Some((_, 'x')) => {
+ if !backslash_x_char(&mut chars) {
+ break;
+ }
+ }
+ Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\'))
+ | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {}
+ Some((_, 'u')) => {
+ if !backslash_u(&mut chars) {
+ break;
+ }
+ }
+ Some((_, '\n')) | Some((_, '\r')) => {
+ while let Some(&(_, ch)) = chars.peek() {
+ if ch.is_whitespace() {
+ chars.next();
+ } else {
+ break;
+ }
+ }
+ }
+ _ => break,
+ },
+ _ch => {}
+ }
+ }
+ Err(LexError)
+}
+
+named!(byte_string -> (), alt!(
+ delimited!(
+ punct!("b\""),
+ cooked_byte_string,
+ tag!("\"")
+ ) => { |_| () }
+ |
+ preceded!(
+ punct!("br"),
+ raw_string
+ ) => { |_| () }
+));
+
+fn cooked_byte_string(mut input: Cursor) -> PResult<()> {
+ let mut bytes = input.bytes().enumerate();
+ 'outer: while let Some((offset, b)) = bytes.next() {
+ match b {
+ b'"' => {
+ return Ok((input.advance(offset), ()));
+ }
+ b'\r' => {
+ if let Some((_, b'\n')) = bytes.next() {
+ // ...
+ } else {
+ break;
+ }
+ }
+ b'\\' => match bytes.next() {
+ Some((_, b'x')) => {
+ if !backslash_x_byte(&mut bytes) {
+ break;
+ }
+ }
+ Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\'))
+ | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {}
+ Some((newline, b'\n')) | Some((newline, b'\r')) => {
+ let rest = input.advance(newline + 1);
+ for (offset, ch) in rest.char_indices() {
+ if !ch.is_whitespace() {
+ input = rest.advance(offset);
+ bytes = input.bytes().enumerate();
+ continue 'outer;
+ }
+ }
+ break;
+ }
+ _ => break,
+ },
+ b if b < 0x80 => {}
+ _ => break,
+ }
+ }
+ Err(LexError)
+}
+
+fn raw_string(input: Cursor) -> PResult<()> {
+ let mut chars = input.char_indices();
+ let mut n = 0;
+ while let Some((byte_offset, ch)) = chars.next() {
+ match ch {
+ '"' => {
+ n = byte_offset;
+ break;
+ }
+ '#' => {}
+ _ => return Err(LexError),
+ }
+ }
+ for (byte_offset, ch) in chars {
+ match ch {
+ '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => {
+ let rest = input.advance(byte_offset + 1 + n);
+ return Ok((rest, ()));
+ }
+ '\r' => {}
+ _ => {}
+ }
+ }
+ Err(LexError)
+}
+
+named!(byte -> (), do_parse!(
+ punct!("b") >>
+ tag!("'") >>
+ cooked_byte >>
+ tag!("'") >>
+ (())
+));
+
+fn cooked_byte(input: Cursor) -> PResult<()> {
+ let mut bytes = input.bytes().enumerate();
+ let ok = match bytes.next().map(|(_, b)| b) {
+ Some(b'\\') => match bytes.next().map(|(_, b)| b) {
+ Some(b'x') => backslash_x_byte(&mut bytes),
+ Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'')
+ | Some(b'"') => true,
+ _ => false,
+ },
+ b => b.is_some(),
+ };
+ if ok {
+ match bytes.next() {
+ Some((offset, _)) => {
+ if input.chars().as_str().is_char_boundary(offset) {
+ Ok((input.advance(offset), ()))
+ } else {
+ Err(LexError)
+ }
+ }
+ None => Ok((input.advance(input.len()), ())),
+ }
+ } else {
+ Err(LexError)
+ }
+}
+
+named!(character -> (), do_parse!(
+ punct!("'") >>
+ cooked_char >>
+ tag!("'") >>
+ (())
+));
+
+fn cooked_char(input: Cursor) -> PResult<()> {
+ let mut chars = input.char_indices();
+ let ok = match chars.next().map(|(_, ch)| ch) {
+ Some('\\') => match chars.next().map(|(_, ch)| ch) {
+ Some('x') => backslash_x_char(&mut chars),
+ Some('u') => backslash_u(&mut chars),
+ Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => {
+ true
+ }
+ _ => false,
+ },
+ ch => ch.is_some(),
+ };
+ if ok {
+ match chars.next() {
+ Some((idx, _)) => Ok((input.advance(idx), ())),
+ None => Ok((input.advance(input.len()), ())),
+ }
+ } else {
+ Err(LexError)
+ }
+}
+
+macro_rules! next_ch {
+ ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
+ match $chars.next() {
+ Some((_, ch)) => match ch {
+ $pat $(| $rest)* => ch,
+ _ => return false,
+ },
+ None => return false
+ }
+ };
+}
+
+fn backslash_x_char<I>(chars: &mut I) -> bool
+where
+ I: Iterator<Item = (usize, char)>,
+{
+ next_ch!(chars @ '0'..='7');
+ next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
+ true
+}
+
+fn backslash_x_byte<I>(chars: &mut I) -> bool
+where
+ I: Iterator<Item = (usize, u8)>,
+{
+ next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
+ next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F');
+ true
+}
+
+fn backslash_u<I>(chars: &mut I) -> bool
+where
+ I: Iterator<Item = (usize, char)>,
+{
+ next_ch!(chars @ '{');
+ next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F');
+ loop {
+ let c = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F' | '_' | '}');
+ if c == '}' {
+ return true;
+ }
+ }
+}
+
+fn float(input: Cursor) -> PResult<()> {
+ let (mut rest, ()) = float_digits(input)?;
+ if let Some(ch) = rest.chars().next() {
+ if is_ident_start(ch) {
+ rest = symbol_not_raw(rest)?.0;
+ }
+ }
+ word_break(rest)
+}
+
+fn float_digits(input: Cursor) -> PResult<()> {
+ let mut chars = input.chars().peekable();
+ match chars.next() {
+ Some(ch) if ch >= '0' && ch <= '9' => {}
+ _ => return Err(LexError),
+ }
+
+ let mut len = 1;
+ let mut has_dot = false;
+ let mut has_exp = false;
+ while let Some(&ch) = chars.peek() {
+ match ch {
+ '0'..='9' | '_' => {
+ chars.next();
+ len += 1;
+ }
+ '.' => {
+ if has_dot {
+ break;
+ }
+ chars.next();
+ if chars
+ .peek()
+ .map(|&ch| ch == '.' || is_ident_start(ch))
+ .unwrap_or(false)
+ {
+ return Err(LexError);
+ }
+ len += 1;
+ has_dot = true;
+ }
+ 'e' | 'E' => {
+ chars.next();
+ len += 1;
+ has_exp = true;
+ break;
+ }
+ _ => break,
+ }
+ }
+
+ let rest = input.advance(len);
+ if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
+ return Err(LexError);
+ }
+
+ if has_exp {
+ let mut has_exp_value = false;
+ while let Some(&ch) = chars.peek() {
+ match ch {
+ '+' | '-' => {
+ if has_exp_value {
+ break;
+ }
+ chars.next();
+ len += 1;
+ }
+ '0'..='9' => {
+ chars.next();
+ len += 1;
+ has_exp_value = true;
+ }
+ '_' => {
+ chars.next();
+ len += 1;
+ }
+ _ => break,
+ }
+ }
+ if !has_exp_value {
+ return Err(LexError);
+ }
+ }
+
+ Ok((input.advance(len), ()))
+}
+
+fn int(input: Cursor) -> PResult<()> {
+ let (mut rest, ()) = digits(input)?;
+ if let Some(ch) = rest.chars().next() {
+ if is_ident_start(ch) {
+ rest = symbol_not_raw(rest)?.0;
+ }
+ }
+ word_break(rest)
+}
+
+fn digits(mut input: Cursor) -> PResult<()> {
+ let base = if input.starts_with("0x") {
+ input = input.advance(2);
+ 16
+ } else if input.starts_with("0o") {
+ input = input.advance(2);
+ 8
+ } else if input.starts_with("0b") {
+ input = input.advance(2);
+ 2
+ } else {
+ 10
+ };
+
+ let mut len = 0;
+ let mut empty = true;
+ for b in input.bytes() {
+ let digit = match b {
+ b'0'..=b'9' => (b - b'0') as u64,
+ b'a'..=b'f' => 10 + (b - b'a') as u64,
+ b'A'..=b'F' => 10 + (b - b'A') as u64,
+ b'_' => {
+ if empty && base == 10 {
+ return Err(LexError);
+ }
+ len += 1;
+ continue;
+ }
+ _ => break,
+ };
+ if digit >= base {
+ return Err(LexError);
+ }
+ len += 1;
+ empty = false;
+ }
+ if empty {
+ Err(LexError)
+ } else {
+ Ok((input.advance(len), ()))
+ }
+}
+
+fn op(input: Cursor) -> PResult<Punct> {
+ let input = skip_whitespace(input);
+ match op_char(input) {
+ Ok((rest, '\'')) => {
+ symbol(rest)?;
+ Ok((rest, Punct::new('\'', Spacing::Joint)))
+ }
+ Ok((rest, ch)) => {
+ let kind = match op_char(rest) {
+ Ok(_) => Spacing::Joint,
+ Err(LexError) => Spacing::Alone,
+ };
+ Ok((rest, Punct::new(ch, kind)))
+ }
+ Err(LexError) => Err(LexError),
+ }
+}
+
+fn op_char(input: Cursor) -> PResult<char> {
+ if input.starts_with("//") || input.starts_with("/*") {
+ // Do not accept `/` of a comment as an op.
+ return Err(LexError);
+ }
+
+ let mut chars = input.chars();
+ let first = match chars.next() {
+ Some(ch) => ch,
+ None => {
+ return Err(LexError);
+ }
+ };
+ let recognized = "~!@#$%^&*-=+|;:,<.>/?'";
+ if recognized.contains(first) {
+ Ok((input.advance(first.len_utf8()), first))
+ } else {
+ Err(LexError)
+ }
+}
+
+fn doc_comment(input: Cursor) -> PResult<Vec<TokenTree>> {
+ let mut trees = Vec::new();
+ let (rest, ((comment, inner), span)) = spanned(input, doc_comment_contents)?;
+ trees.push(TokenTree::Punct(Punct::new('#', Spacing::Alone)));
+ if inner {
+ trees.push(Punct::new('!', Spacing::Alone).into());
+ }
+ let mut stream = vec![
+ TokenTree::Ident(crate::Ident::new("doc", span)),
+ TokenTree::Punct(Punct::new('=', Spacing::Alone)),
+ TokenTree::Literal(crate::Literal::string(comment)),
+ ];
+ for tt in stream.iter_mut() {
+ tt.set_span(span);
+ }
+ let group = Group::new(Delimiter::Bracket, stream.into_iter().collect());
+ trees.push(crate::Group::_new_stable(group).into());
+ for tt in trees.iter_mut() {
+ tt.set_span(span);
+ }
+ Ok((rest, trees))
+}
+
+named!(doc_comment_contents -> (&str, bool), alt!(
+ do_parse!(
+ punct!("//!") >>
+ s: take_until_newline_or_eof!() >>
+ ((s, true))
+ )
+ |
+ do_parse!(
+ option!(whitespace) >>
+ peek!(tag!("/*!")) >>
+ s: block_comment >>
+ ((s, true))
+ )
+ |
+ do_parse!(
+ punct!("///") >>
+ not!(tag!("/")) >>
+ s: take_until_newline_or_eof!() >>
+ ((s, false))
+ )
+ |
+ do_parse!(
+ option!(whitespace) >>
+ peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
+ s: block_comment >>
+ ((s, false))
+ )
+));
diff --git a/proc-macro2/src/lib.rs b/proc-macro2/src/lib.rs
new file mode 100644
index 0000000..bbfb375
--- /dev/null
+++ b/proc-macro2/src/lib.rs
@@ -0,0 +1,1199 @@
+//! A wrapper around the procedural macro API of the compiler's [`proc_macro`]
+//! crate. This library serves two purposes:
+//!
+//! [`proc_macro`]: https://doc.rust-lang.org/proc_macro/
+//!
+//! - **Bring proc-macro-like functionality to other contexts like build.rs and
+//! main.rs.** Types from `proc_macro` are entirely specific to procedural
+//! macros and cannot ever exist in code outside of a procedural macro.
+//! Meanwhile `proc_macro2` types may exist anywhere including non-macro code.
+//! By developing foundational libraries like [syn] and [quote] against
+//! `proc_macro2` rather than `proc_macro`, the procedural macro ecosystem
+//! becomes easily applicable to many other use cases and we avoid
+//! reimplementing non-macro equivalents of those libraries.
+//!
+//! - **Make procedural macros unit testable.** As a consequence of being
+//! specific to procedural macros, nothing that uses `proc_macro` can be
+//! executed from a unit test. In order for helper libraries or components of
+//! a macro to be testable in isolation, they must be implemented using
+//! `proc_macro2`.
+//!
+//! [syn]: https://github.com/dtolnay/syn
+//! [quote]: https://github.com/dtolnay/quote
+//!
+//! # Usage
+//!
+//! The skeleton of a typical procedural macro typically looks like this:
+//!
+//! ```
+//! extern crate proc_macro;
+//!
+//! # const IGNORE: &str = stringify! {
+//! #[proc_macro_derive(MyDerive)]
+//! # };
+//! # #[cfg(wrap_proc_macro)]
+//! pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+//! let input = proc_macro2::TokenStream::from(input);
+//!
+//! let output: proc_macro2::TokenStream = {
+//! /* transform input */
+//! # input
+//! };
+//!
+//! proc_macro::TokenStream::from(output)
+//! }
+//! ```
+//!
+//! If parsing with [Syn], you'll use [`parse_macro_input!`] instead to
+//! propagate parse errors correctly back to the compiler when parsing fails.
+//!
+//! [`parse_macro_input!`]: https://docs.rs/syn/1.0/syn/macro.parse_macro_input.html
+//!
+//! # Unstable features
+//!
+//! The default feature set of proc-macro2 tracks the most recent stable
+//! compiler API. Functionality in `proc_macro` that is not yet stable is not
+//! exposed by proc-macro2 by default.
+//!
+//! To opt into the additional APIs available in the most recent nightly
+//! compiler, the `procmacro2_semver_exempt` config flag must be passed to
+//! rustc. We will polyfill those nightly-only APIs back to Rust 1.31.0. As
+//! these are unstable APIs that track the nightly compiler, minor versions of
+//! proc-macro2 may make breaking changes to them at any time.
+//!
+//! ```sh
+//! RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build
+//! ```
+//!
+//! Note that this must not only be done for your crate, but for any crate that
+//! depends on your crate. This infectious nature is intentional, as it serves
+//! as a reminder that you are outside of the normal semver guarantees.
+//!
+//! Semver exempt methods are marked as such in the proc-macro2 documentation.
+//!
+//! # Thread-Safety
+//!
+//! Most types in this crate are `!Sync` because the underlying compiler
+//! types make use of thread-local memory, meaning they cannot be accessed from
+//! a different thread.
+
+// Proc-macro2 types in rustdoc of other crates get linked to here.
+#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.7")]
+#![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))]
+#![cfg_attr(super_unstable, feature(proc_macro_raw_ident, proc_macro_def_site))]
+
+#[cfg(use_proc_macro)]
+extern crate proc_macro;
+
+use std::cmp::Ordering;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::iter::FromIterator;
+use std::marker;
+use std::ops::RangeBounds;
+#[cfg(procmacro2_semver_exempt)]
+use std::path::PathBuf;
+use std::rc::Rc;
+use std::str::FromStr;
+
+#[macro_use]
+mod strnom;
+mod fallback;
+
+#[cfg(not(wrap_proc_macro))]
+use crate::fallback as imp;
+#[path = "wrapper.rs"]
+#[cfg(wrap_proc_macro)]
+mod imp;
+
+/// An abstract stream of tokens, or more concretely a sequence of token trees.
+///
+/// This type provides interfaces for iterating over token trees and for
+/// collecting token trees into one stream.
+///
+/// Token stream is both the input and output of `#[proc_macro]`,
+/// `#[proc_macro_attribute]` and `#[proc_macro_derive]` definitions.
+#[derive(Clone)]
+pub struct TokenStream {
+ inner: imp::TokenStream,
+ _marker: marker::PhantomData<Rc<()>>,
+}
+
+/// Error returned from `TokenStream::from_str`.
+pub struct LexError {
+ inner: imp::LexError,
+ _marker: marker::PhantomData<Rc<()>>,
+}
+
+impl TokenStream {
+ fn _new(inner: imp::TokenStream) -> TokenStream {
+ TokenStream {
+ inner,
+ _marker: marker::PhantomData,
+ }
+ }
+
+ fn _new_stable(inner: fallback::TokenStream) -> TokenStream {
+ TokenStream {
+ inner: inner.into(),
+ _marker: marker::PhantomData,
+ }
+ }
+
+ /// Returns an empty `TokenStream` containing no token trees.
+ pub fn new() -> TokenStream {
+ TokenStream::_new(imp::TokenStream::new())
+ }
+
+ /// Checks if this `TokenStream` is empty.
+ pub fn is_empty(&self) -> bool {
+ self.inner.is_empty()
+ }
+}
+
+/// `TokenStream::default()` returns an empty stream,
+/// i.e. this is equivalent with `TokenStream::new()`.
+impl Default for TokenStream {
+ fn default() -> Self {
+ TokenStream::new()
+ }
+}
+
+/// Attempts to break the string into tokens and parse those tokens into a token
+/// stream.
+///
+/// May fail for a number of reasons, for example, if the string contains
+/// unbalanced delimiters or characters not existing in the language.
+///
+/// NOTE: Some errors may cause panics instead of returning `LexError`. We
+/// reserve the right to change these errors into `LexError`s later.
+impl FromStr for TokenStream {
+ type Err = LexError;
+
+ fn from_str(src: &str) -> Result<TokenStream, LexError> {
+ let e = src.parse().map_err(|e| LexError {
+ inner: e,
+ _marker: marker::PhantomData,
+ })?;
+ Ok(TokenStream::_new(e))
+ }
+}
+
+#[cfg(use_proc_macro)]
+impl From<proc_macro::TokenStream> for TokenStream {
+ fn from(inner: proc_macro::TokenStream) -> TokenStream {
+ TokenStream::_new(inner.into())
+ }
+}
+
+#[cfg(use_proc_macro)]
+impl From<TokenStream> for proc_macro::TokenStream {
+ fn from(inner: TokenStream) -> proc_macro::TokenStream {
+ inner.inner.into()
+ }
+}
+
+impl From<TokenTree> for TokenStream {
+ fn from(token: TokenTree) -> Self {
+ TokenStream::_new(imp::TokenStream::from(token))
+ }
+}
+
+impl Extend<TokenTree> for TokenStream {
+ fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) {
+ self.inner.extend(streams)
+ }
+}
+
+impl Extend<TokenStream> for TokenStream {
+ fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
+ self.inner
+ .extend(streams.into_iter().map(|stream| stream.inner))
+ }
+}
+
+/// Collects a number of token trees into a single stream.
+impl FromIterator<TokenTree> for TokenStream {
+ fn from_iter<I: IntoIterator<Item = TokenTree>>(streams: I) -> Self {
+ TokenStream::_new(streams.into_iter().collect())
+ }
+}
+impl FromIterator<TokenStream> for TokenStream {
+ fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
+ TokenStream::_new(streams.into_iter().map(|i| i.inner).collect())
+ }
+}
+
+/// Prints the token stream as a string that is supposed to be losslessly
+/// convertible back into the same token stream (modulo spans), except for
+/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and negative
+/// numeric literals.
+impl fmt::Display for TokenStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+/// Prints token in a form convenient for debugging.
+impl fmt::Debug for TokenStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl fmt::Debug for LexError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+/// The source file of a given `Span`.
+///
+/// This type is semver exempt and not exposed by default.
+#[cfg(procmacro2_semver_exempt)]
+#[derive(Clone, PartialEq, Eq)]
+pub struct SourceFile {
+ inner: imp::SourceFile,
+ _marker: marker::PhantomData<Rc<()>>,
+}
+
+#[cfg(procmacro2_semver_exempt)]
+impl SourceFile {
+ fn _new(inner: imp::SourceFile) -> Self {
+ SourceFile {
+ inner,
+ _marker: marker::PhantomData,
+ }
+ }
+
+ /// Get the path to this source file.
+ ///
+ /// ### Note
+ ///
+ /// If the code span associated with this `SourceFile` was generated by an
+ /// external macro, this may not be an actual path on the filesystem. Use
+ /// [`is_real`] to check.
+ ///
+ /// Also note that even if `is_real` returns `true`, if
+ /// `--remap-path-prefix` was passed on the command line, the path as given
+ /// may not actually be valid.
+ ///
+ /// [`is_real`]: #method.is_real
+ pub fn path(&self) -> PathBuf {
+ self.inner.path()
+ }
+
+ /// Returns `true` if this source file is a real source file, and not
+ /// generated by an external macro's expansion.
+ pub fn is_real(&self) -> bool {
+ self.inner.is_real()
+ }
+}
+
+#[cfg(procmacro2_semver_exempt)]
+impl fmt::Debug for SourceFile {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+/// A line-column pair representing the start or end of a `Span`.
+///
+/// This type is semver exempt and not exposed by default.
+#[cfg(span_locations)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct LineColumn {
+ /// The 1-indexed line in the source file on which the span starts or ends
+ /// (inclusive).
+ pub line: usize,
+ /// The 0-indexed column (in UTF-8 characters) in the source file on which
+ /// the span starts or ends (inclusive).
+ pub column: usize,
+}
+
+/// A region of source code, along with macro expansion information.
+#[derive(Copy, Clone)]
+pub struct Span {
+ inner: imp::Span,
+ _marker: marker::PhantomData<Rc<()>>,
+}
+
+impl Span {
+ fn _new(inner: imp::Span) -> Span {
+ Span {
+ inner,
+ _marker: marker::PhantomData,
+ }
+ }
+
+ fn _new_stable(inner: fallback::Span) -> Span {
+ Span {
+ inner: inner.into(),
+ _marker: marker::PhantomData,
+ }
+ }
+
+ /// The span of the invocation of the current procedural macro.
+ ///
+ /// Identifiers created with this span will be resolved as if they were
+ /// written directly at the macro call location (call-site hygiene) and
+ /// other code at the macro call site will be able to refer to them as well.
+ pub fn call_site() -> Span {
+ Span::_new(imp::Span::call_site())
+ }
+
+ /// A span that resolves at the macro definition site.
+ ///
+ /// This method is semver exempt and not exposed by default.
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn def_site() -> Span {
+ Span::_new(imp::Span::def_site())
+ }
+
+ /// Creates a new span with the same line/column information as `self` but
+ /// that resolves symbols as though it were at `other`.
+ ///
+ /// This method is semver exempt and not exposed by default.
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn resolved_at(&self, other: Span) -> Span {
+ Span::_new(self.inner.resolved_at(other.inner))
+ }
+
+ /// Creates a new span with the same name resolution behavior as `self` but
+ /// with the line/column information of `other`.
+ ///
+ /// This method is semver exempt and not exposed by default.
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn located_at(&self, other: Span) -> Span {
+ Span::_new(self.inner.located_at(other.inner))
+ }
+
+ /// Convert `proc_macro2::Span` to `proc_macro::Span`.
+ ///
+ /// This method is available when building with a nightly compiler, or when
+ /// building with rustc 1.29+ *without* semver exempt features.
+ ///
+ /// # Panics
+ ///
+ /// Panics if called from outside of a procedural macro. Unlike
+ /// `proc_macro2::Span`, the `proc_macro::Span` type can only exist within
+ /// the context of a procedural macro invocation.
+ #[cfg(wrap_proc_macro)]
+ pub fn unwrap(self) -> proc_macro::Span {
+ self.inner.unwrap()
+ }
+
+ // Soft deprecated. Please use Span::unwrap.
+ #[cfg(wrap_proc_macro)]
+ #[doc(hidden)]
+ pub fn unstable(self) -> proc_macro::Span {
+ self.unwrap()
+ }
+
+ /// The original source file into which this span points.
+ ///
+ /// This method is semver exempt and not exposed by default.
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn source_file(&self) -> SourceFile {
+ SourceFile::_new(self.inner.source_file())
+ }
+
+ /// Get the starting line/column in the source file for this span.
+ ///
+ /// This method requires the `"span-locations"` feature to be enabled.
+ #[cfg(span_locations)]
+ pub fn start(&self) -> LineColumn {
+ let imp::LineColumn { line, column } = self.inner.start();
+ LineColumn { line, column }
+ }
+
+ /// Get the ending line/column in the source file for this span.
+ ///
+ /// This method requires the `"span-locations"` feature to be enabled.
+ #[cfg(span_locations)]
+ pub fn end(&self) -> LineColumn {
+ let imp::LineColumn { line, column } = self.inner.end();
+ LineColumn { line, column }
+ }
+
+ /// Create a new span encompassing `self` and `other`.
+ ///
+ /// Returns `None` if `self` and `other` are from different files.
+ ///
+ /// Warning: the underlying [`proc_macro::Span::join`] method is
+ /// nightly-only. When called from within a procedural macro not using a
+ /// nightly compiler, this method will always return `None`.
+ ///
+ /// [`proc_macro::Span::join`]: https://doc.rust-lang.org/proc_macro/struct.Span.html#method.join
+ pub fn join(&self, other: Span) -> Option<Span> {
+ self.inner.join(other.inner).map(Span::_new)
+ }
+
+ /// Compares two spans to see if they're equal.
+ ///
+ /// This method is semver exempt and not exposed by default.
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn eq(&self, other: &Span) -> bool {
+ self.inner.eq(&other.inner)
+ }
+}
+
+/// Prints a span in a form convenient for debugging.
+impl fmt::Debug for Span {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
+#[derive(Clone)]
+pub enum TokenTree {
+ /// A token stream surrounded by bracket delimiters.
+ Group(Group),
+ /// An identifier.
+ Ident(Ident),
+ /// A single punctuation character (`+`, `,`, `$`, etc.).
+ Punct(Punct),
+ /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc.
+ Literal(Literal),
+}
+
+impl TokenTree {
+ /// Returns the span of this tree, delegating to the `span` method of
+ /// the contained token or a delimited stream.
+ pub fn span(&self) -> Span {
+ match *self {
+ TokenTree::Group(ref t) => t.span(),
+ TokenTree::Ident(ref t) => t.span(),
+ TokenTree::Punct(ref t) => t.span(),
+ TokenTree::Literal(ref t) => t.span(),
+ }
+ }
+
+ /// Configures the span for *only this token*.
+ ///
+ /// Note that if this token is a `Group` then this method will not configure
+ /// the span of each of the internal tokens, this will simply delegate to
+ /// the `set_span` method of each variant.
+ pub fn set_span(&mut self, span: Span) {
+ match *self {
+ TokenTree::Group(ref mut t) => t.set_span(span),
+ TokenTree::Ident(ref mut t) => t.set_span(span),
+ TokenTree::Punct(ref mut t) => t.set_span(span),
+ TokenTree::Literal(ref mut t) => t.set_span(span),
+ }
+ }
+}
+
+impl From<Group> for TokenTree {
+ fn from(g: Group) -> TokenTree {
+ TokenTree::Group(g)
+ }
+}
+
+impl From<Ident> for TokenTree {
+ fn from(g: Ident) -> TokenTree {
+ TokenTree::Ident(g)
+ }
+}
+
+impl From<Punct> for TokenTree {
+ fn from(g: Punct) -> TokenTree {
+ TokenTree::Punct(g)
+ }
+}
+
+impl From<Literal> for TokenTree {
+ fn from(g: Literal) -> TokenTree {
+ TokenTree::Literal(g)
+ }
+}
+
+/// Prints the token tree as a string that is supposed to be losslessly
+/// convertible back into the same token tree (modulo spans), except for
+/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and negative
+/// numeric literals.
+impl fmt::Display for TokenTree {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ TokenTree::Group(ref t) => t.fmt(f),
+ TokenTree::Ident(ref t) => t.fmt(f),
+ TokenTree::Punct(ref t) => t.fmt(f),
+ TokenTree::Literal(ref t) => t.fmt(f),
+ }
+ }
+}
+
+/// Prints token tree in a form convenient for debugging.
+impl fmt::Debug for TokenTree {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // Each of these has the name in the struct type in the derived debug,
+ // so don't bother with an extra layer of indirection
+ match *self {
+ TokenTree::Group(ref t) => t.fmt(f),
+ TokenTree::Ident(ref t) => {
+ let mut debug = f.debug_struct("Ident");
+ debug.field("sym", &format_args!("{}", t));
+ imp::debug_span_field_if_nontrivial(&mut debug, t.span().inner);
+ debug.finish()
+ }
+ TokenTree::Punct(ref t) => t.fmt(f),
+ TokenTree::Literal(ref t) => t.fmt(f),
+ }
+ }
+}
+
+/// A delimited token stream.
+///
+/// A `Group` internally contains a `TokenStream` which is surrounded by
+/// `Delimiter`s.
+#[derive(Clone)]
+pub struct Group {
+ inner: imp::Group,
+}
+
+/// Describes how a sequence of token trees is delimited.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Delimiter {
+ /// `( ... )`
+ Parenthesis,
+ /// `{ ... }`
+ Brace,
+ /// `[ ... ]`
+ Bracket,
+ /// `Ø ... Ø`
+ ///
+ /// An implicit delimiter, that may, for example, appear around tokens
+ /// coming from a "macro variable" `$var`. It is important to preserve
+ /// operator priorities in cases like `$var * 3` where `$var` is `1 + 2`.
+ /// Implicit delimiters may not survive roundtrip of a token stream through
+ /// a string.
+ None,
+}
+
+impl Group {
+ fn _new(inner: imp::Group) -> Self {
+ Group { inner }
+ }
+
+ fn _new_stable(inner: fallback::Group) -> Self {
+ Group {
+ inner: inner.into(),
+ }
+ }
+
+ /// Creates a new `Group` with the given delimiter and token stream.
+ ///
+ /// This constructor will set the span for this group to
+ /// `Span::call_site()`. To change the span you can use the `set_span`
+ /// method below.
+ pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
+ Group {
+ inner: imp::Group::new(delimiter, stream.inner),
+ }
+ }
+
+ /// Returns the delimiter of this `Group`
+ pub fn delimiter(&self) -> Delimiter {
+ self.inner.delimiter()
+ }
+
+ /// Returns the `TokenStream` of tokens that are delimited in this `Group`.
+ ///
+ /// Note that the returned token stream does not include the delimiter
+ /// returned above.
+ pub fn stream(&self) -> TokenStream {
+ TokenStream::_new(self.inner.stream())
+ }
+
+ /// Returns the span for the delimiters of this token stream, spanning the
+ /// entire `Group`.
+ ///
+ /// ```text
+ /// pub fn span(&self) -> Span {
+ /// ^^^^^^^
+ /// ```
+ pub fn span(&self) -> Span {
+ Span::_new(self.inner.span())
+ }
+
+ /// Returns the span pointing to the opening delimiter of this group.
+ ///
+ /// ```text
+ /// pub fn span_open(&self) -> Span {
+ /// ^
+ /// ```
+ pub fn span_open(&self) -> Span {
+ Span::_new(self.inner.span_open())
+ }
+
+ /// Returns the span pointing to the closing delimiter of this group.
+ ///
+ /// ```text
+ /// pub fn span_close(&self) -> Span {
+ /// ^
+ /// ```
+ pub fn span_close(&self) -> Span {
+ Span::_new(self.inner.span_close())
+ }
+
+ /// Configures the span for this `Group`'s delimiters, but not its internal
+ /// tokens.
+ ///
+ /// This method will **not** set the span of all the internal tokens spanned
+ /// by this group, but rather it will only set the span of the delimiter
+ /// tokens at the level of the `Group`.
+ pub fn set_span(&mut self, span: Span) {
+ self.inner.set_span(span.inner)
+ }
+}
+
+/// Prints the group as a string that should be losslessly convertible back
+/// into the same group (modulo spans), except for possibly `TokenTree::Group`s
+/// with `Delimiter::None` delimiters.
+impl fmt::Display for Group {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.inner, formatter)
+ }
+}
+
+impl fmt::Debug for Group {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, formatter)
+ }
+}
+
+/// An `Punct` is an single punctuation character like `+`, `-` or `#`.
+///
+/// Multicharacter operators like `+=` are represented as two instances of
+/// `Punct` with different forms of `Spacing` returned.
+#[derive(Clone)]
+pub struct Punct {
+ op: char,
+ spacing: Spacing,
+ span: Span,
+}
+
+/// Whether an `Punct` is followed immediately by another `Punct` or followed by
+/// another token or whitespace.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Spacing {
+ /// E.g. `+` is `Alone` in `+ =`, `+ident` or `+()`.
+ Alone,
+ /// E.g. `+` is `Joint` in `+=` or `'` is `Joint` in `'#`.
+ ///
+ /// Additionally, single quote `'` can join with identifiers to form
+ /// lifetimes `'ident`.
+ Joint,
+}
+
+impl Punct {
+ /// Creates a new `Punct` from the given character and spacing.
+ ///
+ /// The `ch` argument must be a valid punctuation character permitted by the
+ /// language, otherwise the function will panic.
+ ///
+ /// The returned `Punct` will have the default span of `Span::call_site()`
+ /// which can be further configured with the `set_span` method below.
+ pub fn new(op: char, spacing: Spacing) -> Punct {
+ Punct {
+ op,
+ spacing,
+ span: Span::call_site(),
+ }
+ }
+
+ /// Returns the value of this punctuation character as `char`.
+ pub fn as_char(&self) -> char {
+ self.op
+ }
+
+ /// Returns the spacing of this punctuation character, indicating whether
+ /// it's immediately followed by another `Punct` in the token stream, so
+ /// they can potentially be combined into a multicharacter operator
+ /// (`Joint`), or it's followed by some other token or whitespace (`Alone`)
+ /// so the operator has certainly ended.
+ pub fn spacing(&self) -> Spacing {
+ self.spacing
+ }
+
+ /// Returns the span for this punctuation character.
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ /// Configure the span for this punctuation character.
+ pub fn set_span(&mut self, span: Span) {
+ self.span = span;
+ }
+}
+
+/// Prints the punctuation character as a string that should be losslessly
+/// convertible back into the same character.
+impl fmt::Display for Punct {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.op.fmt(f)
+ }
+}
+
+impl fmt::Debug for Punct {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut debug = fmt.debug_struct("Punct");
+ debug.field("op", &self.op);
+ debug.field("spacing", &self.spacing);
+ imp::debug_span_field_if_nontrivial(&mut debug, self.span.inner);
+ debug.finish()
+ }
+}
+
+/// A word of Rust code, which may be a keyword or legal variable name.
+///
+/// An identifier consists of at least one Unicode code point, the first of
+/// which has the XID_Start property and the rest of which have the XID_Continue
+/// property.
+///
+/// - The empty string is not an identifier. Use `Option<Ident>`.
+/// - A lifetime is not an identifier. Use `syn::Lifetime` instead.
+///
+/// An identifier constructed with `Ident::new` is permitted to be a Rust
+/// keyword, though parsing one through its [`Parse`] implementation rejects
+/// Rust keywords. Use `input.call(Ident::parse_any)` when parsing to match the
+/// behaviour of `Ident::new`.
+///
+/// [`Parse`]: https://docs.rs/syn/1.0/syn/parse/trait.Parse.html
+///
+/// # Examples
+///
+/// A new ident can be created from a string using the `Ident::new` function.
+/// A span must be provided explicitly which governs the name resolution
+/// behavior of the resulting identifier.
+///
+/// ```
+/// use proc_macro2::{Ident, Span};
+///
+/// fn main() {
+/// let call_ident = Ident::new("calligraphy", Span::call_site());
+///
+/// println!("{}", call_ident);
+/// }
+/// ```
+///
+/// An ident can be interpolated into a token stream using the `quote!` macro.
+///
+/// ```
+/// use proc_macro2::{Ident, Span};
+/// use quote::quote;
+///
+/// fn main() {
+/// let ident = Ident::new("demo", Span::call_site());
+///
+/// // Create a variable binding whose name is this ident.
+/// let expanded = quote! { let #ident = 10; };
+///
+/// // Create a variable binding with a slightly different name.
+/// let temp_ident = Ident::new(&format!("new_{}", ident), Span::call_site());
+/// let expanded = quote! { let #temp_ident = 10; };
+/// }
+/// ```
+///
+/// A string representation of the ident is available through the `to_string()`
+/// method.
+///
+/// ```
+/// # use proc_macro2::{Ident, Span};
+/// #
+/// # let ident = Ident::new("another_identifier", Span::call_site());
+/// #
+/// // Examine the ident as a string.
+/// let ident_string = ident.to_string();
+/// if ident_string.len() > 60 {
+/// println!("Very long identifier: {}", ident_string)
+/// }
+/// ```
+#[derive(Clone)]
+pub struct Ident {
+ inner: imp::Ident,
+ _marker: marker::PhantomData<Rc<()>>,
+}
+
+impl Ident {
+ fn _new(inner: imp::Ident) -> Ident {
+ Ident {
+ inner,
+ _marker: marker::PhantomData,
+ }
+ }
+
+ /// Creates a new `Ident` with the given `string` as well as the specified
+ /// `span`.
+ ///
+ /// The `string` argument must be a valid identifier permitted by the
+ /// language, otherwise the function will panic.
+ ///
+ /// Note that `span`, currently in rustc, configures the hygiene information
+ /// for this identifier.
+ ///
+ /// As of this time `Span::call_site()` explicitly opts-in to "call-site"
+ /// hygiene meaning that identifiers created with this span will be resolved
+ /// as if they were written directly at the location of the macro call, and
+ /// other code at the macro call site will be able to refer to them as well.
+ ///
+ /// Later spans like `Span::def_site()` will allow to opt-in to
+ /// "definition-site" hygiene meaning that identifiers created with this
+ /// span will be resolved at the location of the macro definition and other
+ /// code at the macro call site will not be able to refer to them.
+ ///
+ /// Due to the current importance of hygiene this constructor, unlike other
+ /// tokens, requires a `Span` to be specified at construction.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the input string is neither a keyword nor a legal variable
+ /// name. If you are not sure whether the string contains an identifier and
+ /// need to handle an error case, use
+ /// <a href="https://docs.rs/syn/1.0/syn/fn.parse_str.html"><code
+ /// style="padding-right:0;">syn::parse_str</code></a><code
+ /// style="padding-left:0;">::&lt;Ident&gt;</code>
+ /// rather than `Ident::new`.
+ pub fn new(string: &str, span: Span) -> Ident {
+ Ident::_new(imp::Ident::new(string, span.inner))
+ }
+
+ /// Same as `Ident::new`, but creates a raw identifier (`r#ident`).
+ ///
+ /// This method is semver exempt and not exposed by default.
+ #[cfg(procmacro2_semver_exempt)]
+ pub fn new_raw(string: &str, span: Span) -> Ident {
+ Ident::_new_raw(string, span)
+ }
+
+ fn _new_raw(string: &str, span: Span) -> Ident {
+ Ident::_new(imp::Ident::new_raw(string, span.inner))
+ }
+
+ /// Returns the span of this `Ident`.
+ pub fn span(&self) -> Span {
+ Span::_new(self.inner.span())
+ }
+
+ /// Configures the span of this `Ident`, possibly changing its hygiene
+ /// context.
+ pub fn set_span(&mut self, span: Span) {
+ self.inner.set_span(span.inner);
+ }
+}
+
+impl PartialEq for Ident {
+ fn eq(&self, other: &Ident) -> bool {
+ self.inner == other.inner
+ }
+}
+
+impl<T> PartialEq<T> for Ident
+where
+ T: ?Sized + AsRef<str>,
+{
+ fn eq(&self, other: &T) -> bool {
+ self.inner == other
+ }
+}
+
+impl Eq for Ident {}
+
+impl PartialOrd for Ident {
+ fn partial_cmp(&self, other: &Ident) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Ident {
+ fn cmp(&self, other: &Ident) -> Ordering {
+ self.to_string().cmp(&other.to_string())
+ }
+}
+
+impl Hash for Ident {
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ self.to_string().hash(hasher)
+ }
+}
+
+/// Prints the identifier as a string that should be losslessly convertible back
+/// into the same identifier.
+impl fmt::Display for Ident {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl fmt::Debug for Ident {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+/// A literal string (`"hello"`), byte string (`b"hello"`), character (`'a'`),
+/// byte character (`b'a'`), an integer or floating point number with or without
+/// a suffix (`1`, `1u8`, `2.3`, `2.3f32`).
+///
+/// Boolean literals like `true` and `false` do not belong here, they are
+/// `Ident`s.
+#[derive(Clone)]
+pub struct Literal {
+ inner: imp::Literal,
+ _marker: marker::PhantomData<Rc<()>>,
+}
+
+macro_rules! suffixed_int_literals {
+ ($($name:ident => $kind:ident,)*) => ($(
+ /// Creates a new suffixed integer literal with the specified value.
+ ///
+ /// This function will create an integer like `1u32` where the integer
+ /// value specified is the first part of the token and the integral is
+ /// also suffixed at the end. Literals created from negative numbers may
+ /// not survive rountrips through `TokenStream` or strings and may be
+ /// broken into two tokens (`-` and positive literal).
+ ///
+ /// Literals created through this method have the `Span::call_site()`
+ /// span by default, which can be configured with the `set_span` method
+ /// below.
+ pub fn $name(n: $kind) -> Literal {
+ Literal::_new(imp::Literal::$name(n))
+ }
+ )*)
+}
+
+macro_rules! unsuffixed_int_literals {
+ ($($name:ident => $kind:ident,)*) => ($(
+ /// Creates a new unsuffixed integer literal with the specified value.
+ ///
+ /// This function will create an integer like `1` where the integer
+ /// value specified is the first part of the token. No suffix is
+ /// specified on this token, meaning that invocations like
+ /// `Literal::i8_unsuffixed(1)` are equivalent to
+ /// `Literal::u32_unsuffixed(1)`. Literals created from negative numbers
+ /// may not survive rountrips through `TokenStream` or strings and may
+ /// be broken into two tokens (`-` and positive literal).
+ ///
+ /// Literals created through this method have the `Span::call_site()`
+ /// span by default, which can be configured with the `set_span` method
+ /// below.
+ pub fn $name(n: $kind) -> Literal {
+ Literal::_new(imp::Literal::$name(n))
+ }
+ )*)
+}
+
+impl Literal {
+ fn _new(inner: imp::Literal) -> Literal {
+ Literal {
+ inner,
+ _marker: marker::PhantomData,
+ }
+ }
+
+ fn _new_stable(inner: fallback::Literal) -> Literal {
+ Literal {
+ inner: inner.into(),
+ _marker: marker::PhantomData,
+ }
+ }
+
+ suffixed_int_literals! {
+ u8_suffixed => u8,
+ u16_suffixed => u16,
+ u32_suffixed => u32,
+ u64_suffixed => u64,
+ u128_suffixed => u128,
+ usize_suffixed => usize,
+ i8_suffixed => i8,
+ i16_suffixed => i16,
+ i32_suffixed => i32,
+ i64_suffixed => i64,
+ i128_suffixed => i128,
+ isize_suffixed => isize,
+ }
+
+ unsuffixed_int_literals! {
+ u8_unsuffixed => u8,
+ u16_unsuffixed => u16,
+ u32_unsuffixed => u32,
+ u64_unsuffixed => u64,
+ u128_unsuffixed => u128,
+ usize_unsuffixed => usize,
+ i8_unsuffixed => i8,
+ i16_unsuffixed => i16,
+ i32_unsuffixed => i32,
+ i64_unsuffixed => i64,
+ i128_unsuffixed => i128,
+ isize_unsuffixed => isize,
+ }
+
+ /// Creates a new unsuffixed floating-point literal.
+ ///
+ /// This constructor is similar to those like `Literal::i8_unsuffixed` where
+ /// the float's value is emitted directly into the token but no suffix is
+ /// used, so it may be inferred to be a `f64` later in the compiler.
+ /// Literals created from negative numbers may not survive rountrips through
+ /// `TokenStream` or strings and may be broken into two tokens (`-` and
+ /// positive literal).
+ ///
+ /// # Panics
+ ///
+ /// This function requires that the specified float is finite, for example
+ /// if it is infinity or NaN this function will panic.
+ pub fn f64_unsuffixed(f: f64) -> Literal {
+ assert!(f.is_finite());
+ Literal::_new(imp::Literal::f64_unsuffixed(f))
+ }
+
+ /// Creates a new suffixed floating-point literal.
+ ///
+ /// This constructor will create a literal like `1.0f64` where the value
+ /// specified is the preceding part of the token and `f64` is the suffix of
+ /// the token. This token will always be inferred to be an `f64` in the
+ /// compiler. Literals created from negative numbers may not survive
+ /// rountrips through `TokenStream` or strings and may be broken into two
+ /// tokens (`-` and positive literal).
+ ///
+ /// # Panics
+ ///
+ /// This function requires that the specified float is finite, for example
+ /// if it is infinity or NaN this function will panic.
+ pub fn f64_suffixed(f: f64) -> Literal {
+ assert!(f.is_finite());
+ Literal::_new(imp::Literal::f64_suffixed(f))
+ }
+
+ /// Creates a new unsuffixed floating-point literal.
+ ///
+ /// This constructor is similar to those like `Literal::i8_unsuffixed` where
+ /// the float's value is emitted directly into the token but no suffix is
+ /// used, so it may be inferred to be a `f64` later in the compiler.
+ /// Literals created from negative numbers may not survive rountrips through
+ /// `TokenStream` or strings and may be broken into two tokens (`-` and
+ /// positive literal).
+ ///
+ /// # Panics
+ ///
+ /// This function requires that the specified float is finite, for example
+ /// if it is infinity or NaN this function will panic.
+ pub fn f32_unsuffixed(f: f32) -> Literal {
+ assert!(f.is_finite());
+ Literal::_new(imp::Literal::f32_unsuffixed(f))
+ }
+
+ /// Creates a new suffixed floating-point literal.
+ ///
+ /// This constructor will create a literal like `1.0f32` where the value
+ /// specified is the preceding part of the token and `f32` is the suffix of
+ /// the token. This token will always be inferred to be an `f32` in the
+ /// compiler. Literals created from negative numbers may not survive
+ /// rountrips through `TokenStream` or strings and may be broken into two
+ /// tokens (`-` and positive literal).
+ ///
+ /// # Panics
+ ///
+ /// This function requires that the specified float is finite, for example
+ /// if it is infinity or NaN this function will panic.
+ pub fn f32_suffixed(f: f32) -> Literal {
+ assert!(f.is_finite());
+ Literal::_new(imp::Literal::f32_suffixed(f))
+ }
+
+ /// String literal.
+ pub fn string(string: &str) -> Literal {
+ Literal::_new(imp::Literal::string(string))
+ }
+
+ /// Character literal.
+ pub fn character(ch: char) -> Literal {
+ Literal::_new(imp::Literal::character(ch))
+ }
+
+ /// Byte string literal.
+ pub fn byte_string(s: &[u8]) -> Literal {
+ Literal::_new(imp::Literal::byte_string(s))
+ }
+
+ /// Returns the span encompassing this literal.
+ pub fn span(&self) -> Span {
+ Span::_new(self.inner.span())
+ }
+
+ /// Configures the span associated for this literal.
+ pub fn set_span(&mut self, span: Span) {
+ self.inner.set_span(span.inner);
+ }
+
+ /// Returns a `Span` that is a subset of `self.span()` containing only
+ /// the source bytes in range `range`. Returns `None` if the would-be
+ /// trimmed span is outside the bounds of `self`.
+ ///
+ /// Warning: the underlying [`proc_macro::Literal::subspan`] method is
+ /// nightly-only. When called from within a procedural macro not using a
+ /// nightly compiler, this method will always return `None`.
+ ///
+ /// [`proc_macro::Literal::subspan`]: https://doc.rust-lang.org/proc_macro/struct.Literal.html#method.subspan
+ pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
+ self.inner.subspan(range).map(Span::_new)
+ }
+}
+
+impl fmt::Debug for Literal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl fmt::Display for Literal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+/// Public implementation details for the `TokenStream` type, such as iterators.
+pub mod token_stream {
+ use std::fmt;
+ use std::marker;
+ use std::rc::Rc;
+
+ pub use crate::TokenStream;
+ use crate::{imp, TokenTree};
+
+ /// An iterator over `TokenStream`'s `TokenTree`s.
+ ///
+ /// The iteration is "shallow", e.g. the iterator doesn't recurse into
+ /// delimited groups, and returns whole groups as token trees.
+ #[derive(Clone)]
+ pub struct IntoIter {
+ inner: imp::TokenTreeIter,
+ _marker: marker::PhantomData<Rc<()>>,
+ }
+
+ impl Iterator for IntoIter {
+ type Item = TokenTree;
+
+ fn next(&mut self) -> Option<TokenTree> {
+ self.inner.next()
+ }
+ }
+
+ impl fmt::Debug for IntoIter {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+ }
+
+ impl IntoIterator for TokenStream {
+ type Item = TokenTree;
+ type IntoIter = IntoIter;
+
+ fn into_iter(self) -> IntoIter {
+ IntoIter {
+ inner: self.inner.into_iter(),
+ _marker: marker::PhantomData,
+ }
+ }
+ }
+}
diff --git a/proc-macro2/src/strnom.rs b/proc-macro2/src/strnom.rs
new file mode 100644
index 0000000..eb7d0b8
--- /dev/null
+++ b/proc-macro2/src/strnom.rs
@@ -0,0 +1,391 @@
+//! Adapted from [`nom`](https://github.com/Geal/nom).
+
+use crate::fallback::LexError;
+use std::str::{Bytes, CharIndices, Chars};
+use unicode_xid::UnicodeXID;
+
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct Cursor<'a> {
+ pub rest: &'a str,
+ #[cfg(span_locations)]
+ pub off: u32,
+}
+
+impl<'a> Cursor<'a> {
+ #[cfg(not(span_locations))]
+ pub fn advance(&self, amt: usize) -> Cursor<'a> {
+ Cursor {
+ rest: &self.rest[amt..],
+ }
+ }
+ #[cfg(span_locations)]
+ pub fn advance(&self, amt: usize) -> Cursor<'a> {
+ Cursor {
+ rest: &self.rest[amt..],
+ off: self.off + (amt as u32),
+ }
+ }
+
+ pub fn find(&self, p: char) -> Option<usize> {
+ self.rest.find(p)
+ }
+
+ pub fn starts_with(&self, s: &str) -> bool {
+ self.rest.starts_with(s)
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.rest.is_empty()
+ }
+
+ pub fn len(&self) -> usize {
+ self.rest.len()
+ }
+
+ pub fn as_bytes(&self) -> &'a [u8] {
+ self.rest.as_bytes()
+ }
+
+ pub fn bytes(&self) -> Bytes<'a> {
+ self.rest.bytes()
+ }
+
+ pub fn chars(&self) -> Chars<'a> {
+ self.rest.chars()
+ }
+
+ pub fn char_indices(&self) -> CharIndices<'a> {
+ self.rest.char_indices()
+ }
+}
+
+pub type PResult<'a, O> = Result<(Cursor<'a>, O), LexError>;
+
+pub fn whitespace(input: Cursor) -> PResult<()> {
+ if input.is_empty() {
+ return Err(LexError);
+ }
+
+ let bytes = input.as_bytes();
+ let mut i = 0;
+ while i < bytes.len() {
+ let s = input.advance(i);
+ if bytes[i] == b'/' {
+ if s.starts_with("//")
+ && (!s.starts_with("///") || s.starts_with("////"))
+ && !s.starts_with("//!")
+ {
+ if let Some(len) = s.find('\n') {
+ i += len + 1;
+ continue;
+ }
+ break;
+ } else if s.starts_with("/**/") {
+ i += 4;
+ continue;
+ } else if s.starts_with("/*")
+ && (!s.starts_with("/**") || s.starts_with("/***"))
+ && !s.starts_with("/*!")
+ {
+ let (_, com) = block_comment(s)?;
+ i += com.len();
+ continue;
+ }
+ }
+ match bytes[i] {
+ b' ' | 0x09..=0x0d => {
+ i += 1;
+ continue;
+ }
+ b if b <= 0x7f => {}
+ _ => {
+ let ch = s.chars().next().unwrap();
+ if is_whitespace(ch) {
+ i += ch.len_utf8();
+ continue;
+ }
+ }
+ }
+ return if i > 0 { Ok((s, ())) } else { Err(LexError) };
+ }
+ Ok((input.advance(input.len()), ()))
+}
+
+pub fn block_comment(input: Cursor) -> PResult<&str> {
+ if !input.starts_with("/*") {
+ return Err(LexError);
+ }
+
+ let mut depth = 0;
+ let bytes = input.as_bytes();
+ let mut i = 0;
+ let upper = bytes.len() - 1;
+ while i < upper {
+ if bytes[i] == b'/' && bytes[i + 1] == b'*' {
+ depth += 1;
+ i += 1; // eat '*'
+ } else if bytes[i] == b'*' && bytes[i + 1] == b'/' {
+ depth -= 1;
+ if depth == 0 {
+ return Ok((input.advance(i + 2), &input.rest[..i + 2]));
+ }
+ i += 1; // eat '/'
+ }
+ i += 1;
+ }
+ Err(LexError)
+}
+
+pub fn skip_whitespace(input: Cursor) -> Cursor {
+ match whitespace(input) {
+ Ok((rest, _)) => rest,
+ Err(LexError) => input,
+ }
+}
+
+fn is_whitespace(ch: char) -> bool {
+ // Rust treats left-to-right mark and right-to-left mark as whitespace
+ ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}'
+}
+
+pub fn word_break(input: Cursor) -> PResult<()> {
+ match input.chars().next() {
+ Some(ch) if UnicodeXID::is_xid_continue(ch) => Err(LexError),
+ Some(_) | None => Ok((input, ())),
+ }
+}
+
+macro_rules! named {
+ ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ fn $name<'a>(i: Cursor<'a>) -> $crate::strnom::PResult<'a, $o> {
+ $submac!(i, $($args)*)
+ }
+ };
+}
+
+macro_rules! alt {
+ ($i:expr, $e:ident | $($rest:tt)*) => {
+ alt!($i, call!($e) | $($rest)*)
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
+ match $subrule!($i, $($args)*) {
+ res @ Ok(_) => res,
+ _ => alt!($i, $($rest)*)
+ }
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
+ match $subrule!($i, $($args)*) {
+ Ok((i, o)) => Ok((i, $gen(o))),
+ Err(LexError) => alt!($i, $($rest)*)
+ }
+ };
+
+ ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
+ alt!($i, call!($e) => { $gen } | $($rest)*)
+ };
+
+ ($i:expr, $e:ident => { $gen:expr }) => {
+ alt!($i, call!($e) => { $gen })
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
+ match $subrule!($i, $($args)*) {
+ Ok((i, o)) => Ok((i, $gen(o))),
+ Err(LexError) => Err(LexError),
+ }
+ };
+
+ ($i:expr, $e:ident) => {
+ alt!($i, call!($e))
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)*)) => {
+ $subrule!($i, $($args)*)
+ };
+}
+
+macro_rules! do_parse {
+ ($i:expr, ( $($rest:expr),* )) => {
+ Ok(($i, ( $($rest),* )))
+ };
+
+ ($i:expr, $e:ident >> $($rest:tt)*) => {
+ do_parse!($i, call!($e) >> $($rest)*)
+ };
+
+ ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ Err(LexError) => Err(LexError),
+ Ok((i, _)) => do_parse!(i, $($rest)*),
+ }
+ };
+
+ ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
+ do_parse!($i, $field: call!($e) >> $($rest)*)
+ };
+
+ ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ Err(LexError) => Err(LexError),
+ Ok((i, o)) => {
+ let $field = o;
+ do_parse!(i, $($rest)*)
+ },
+ }
+ };
+}
+
+macro_rules! peek {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ Ok((_, o)) => Ok(($i, o)),
+ Err(LexError) => Err(LexError),
+ }
+ };
+}
+
+macro_rules! call {
+ ($i:expr, $fun:expr $(, $args:expr)*) => {
+ $fun($i $(, $args)*)
+ };
+}
+
+macro_rules! option {
+ ($i:expr, $f:expr) => {
+ match $f($i) {
+ Ok((i, o)) => Ok((i, Some(o))),
+ Err(LexError) => Ok(($i, None)),
+ }
+ };
+}
+
+macro_rules! take_until_newline_or_eof {
+ ($i:expr,) => {{
+ if $i.len() == 0 {
+ Ok(($i, ""))
+ } else {
+ match $i.find('\n') {
+ Some(i) => Ok(($i.advance(i), &$i.rest[..i])),
+ None => Ok(($i.advance($i.len()), &$i.rest[..$i.len()])),
+ }
+ }
+ }};
+}
+
+macro_rules! tuple {
+ ($i:expr, $($rest:tt)*) => {
+ tuple_parser!($i, (), $($rest)*)
+ };
+}
+
+/// Do not use directly. Use `tuple!`.
+macro_rules! tuple_parser {
+ ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => {
+ tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*)
+ };
+
+ ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ Err(LexError) => Err(LexError),
+ Ok((i, o)) => tuple_parser!(i, (o), $($rest)*),
+ }
+ };
+
+ ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ Err(LexError) => Err(LexError),
+ Ok((i, o)) => tuple_parser!(i, ($($parsed)* , o), $($rest)*),
+ }
+ };
+
+ ($i:expr, ($($parsed:tt),*), $e:ident) => {
+ tuple_parser!($i, ($($parsed),*), call!($e))
+ };
+
+ ($i:expr, (), $submac:ident!( $($args:tt)* )) => {
+ $submac!($i, $($args)*)
+ };
+
+ ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ Err(LexError) => Err(LexError),
+ Ok((i, o)) => Ok((i, ($($parsed),*, o)))
+ }
+ };
+
+ ($i:expr, ($($parsed:expr),*)) => {
+ Ok(($i, ($($parsed),*)))
+ };
+}
+
+macro_rules! not {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ Ok((_, _)) => Err(LexError),
+ Err(LexError) => Ok(($i, ())),
+ }
+ };
+}
+
+macro_rules! tag {
+ ($i:expr, $tag:expr) => {
+ if $i.starts_with($tag) {
+ Ok(($i.advance($tag.len()), &$i.rest[..$tag.len()]))
+ } else {
+ Err(LexError)
+ }
+ };
+}
+
+macro_rules! punct {
+ ($i:expr, $punct:expr) => {
+ $crate::strnom::punct($i, $punct)
+ };
+}
+
+/// Do not use directly. Use `punct!`.
+pub fn punct<'a>(input: Cursor<'a>, token: &'static str) -> PResult<'a, &'a str> {
+ let input = skip_whitespace(input);
+ if input.starts_with(token) {
+ Ok((input.advance(token.len()), token))
+ } else {
+ Err(LexError)
+ }
+}
+
+macro_rules! preceded {
+ ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => {
+ match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) {
+ Ok((remaining, (_, o))) => Ok((remaining, o)),
+ Err(LexError) => Err(LexError),
+ }
+ };
+
+ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
+ preceded!($i, $submac!($($args)*), call!($g))
+ };
+}
+
+macro_rules! delimited {
+ ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => {
+ match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) {
+ Err(LexError) => Err(LexError),
+ Ok((i1, (_, o, _))) => Ok((i1, o))
+ }
+ };
+}
+
+macro_rules! map {
+ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
+ match $submac!($i, $($args)*) {
+ Err(LexError) => Err(LexError),
+ Ok((i, o)) => Ok((i, call!(o, $g)))
+ }
+ };
+
+ ($i:expr, $f:expr, $g:expr) => {
+ map!($i, call!($f), $g)
+ };
+}
diff --git a/proc-macro2/src/wrapper.rs b/proc-macro2/src/wrapper.rs
new file mode 100644
index 0000000..552b938
--- /dev/null
+++ b/proc-macro2/src/wrapper.rs
@@ -0,0 +1,927 @@
+use std::fmt;
+use std::iter;
+use std::ops::RangeBounds;
+use std::panic::{self, PanicInfo};
+#[cfg(super_unstable)]
+use std::path::PathBuf;
+use std::str::FromStr;
+
+use crate::{fallback, Delimiter, Punct, Spacing, TokenTree};
+
+#[derive(Clone)]
+pub enum TokenStream {
+ Compiler(DeferredTokenStream),
+ Fallback(fallback::TokenStream),
+}
+
+// Work around https://github.com/rust-lang/rust/issues/65080.
+// In `impl Extend<TokenTree> for TokenStream` which is used heavily by quote,
+// we hold on to the appended tokens and do proc_macro::TokenStream::extend as
+// late as possible to batch together consecutive uses of the Extend impl.
+#[derive(Clone)]
+pub struct DeferredTokenStream {
+ stream: proc_macro::TokenStream,
+ extra: Vec<proc_macro::TokenTree>,
+}
+
+pub enum LexError {
+ Compiler(proc_macro::LexError),
+ Fallback(fallback::LexError),
+}
+
+fn nightly_works() -> bool {
+ use std::sync::atomic::*;
+ use std::sync::Once;
+
+ static WORKS: AtomicUsize = AtomicUsize::new(0);
+ static INIT: Once = Once::new();
+
+ match WORKS.load(Ordering::SeqCst) {
+ 1 => return false,
+ 2 => return true,
+ _ => {}
+ }
+
+ // Swap in a null panic hook to avoid printing "thread panicked" to stderr,
+ // then use catch_unwind to determine whether the compiler's proc_macro is
+ // working. When proc-macro2 is used from outside of a procedural macro all
+ // of the proc_macro crate's APIs currently panic.
+ //
+ // The Once is to prevent the possibility of this ordering:
+ //
+ // thread 1 calls take_hook, gets the user's original hook
+ // thread 1 calls set_hook with the null hook
+ // thread 2 calls take_hook, thinks null hook is the original hook
+ // thread 2 calls set_hook with the null hook
+ // thread 1 calls set_hook with the actual original hook
+ // thread 2 calls set_hook with what it thinks is the original hook
+ //
+ // in which the user's hook has been lost.
+ //
+ // There is still a race condition where a panic in a different thread can
+ // happen during the interval that the user's original panic hook is
+ // unregistered such that their hook is incorrectly not called. This is
+ // sufficiently unlikely and less bad than printing panic messages to stderr
+ // on correct use of this crate. Maybe there is a libstd feature request
+ // here. For now, if a user needs to guarantee that this failure mode does
+ // not occur, they need to call e.g. `proc_macro2::Span::call_site()` from
+ // the main thread before launching any other threads.
+ INIT.call_once(|| {
+ type PanicHook = dyn Fn(&PanicInfo) + Sync + Send + 'static;
+
+ let null_hook: Box<PanicHook> = Box::new(|_panic_info| { /* ignore */ });
+ let sanity_check = &*null_hook as *const PanicHook;
+ let original_hook = panic::take_hook();
+ panic::set_hook(null_hook);
+
+ let works = panic::catch_unwind(|| proc_macro::Span::call_site()).is_ok();
+ WORKS.store(works as usize + 1, Ordering::SeqCst);
+
+ let hopefully_null_hook = panic::take_hook();
+ panic::set_hook(original_hook);
+ if sanity_check != &*hopefully_null_hook {
+ panic!("observed race condition in proc_macro2::nightly_works");
+ }
+ });
+ nightly_works()
+}
+
+fn mismatch() -> ! {
+ panic!("stable/nightly mismatch")
+}
+
+impl DeferredTokenStream {
+ fn new(stream: proc_macro::TokenStream) -> Self {
+ DeferredTokenStream {
+ stream,
+ extra: Vec::new(),
+ }
+ }
+
+ fn is_empty(&self) -> bool {
+ self.stream.is_empty() && self.extra.is_empty()
+ }
+
+ fn evaluate_now(&mut self) {
+ self.stream.extend(self.extra.drain(..));
+ }
+
+ fn into_token_stream(mut self) -> proc_macro::TokenStream {
+ self.evaluate_now();
+ self.stream
+ }
+}
+
+impl TokenStream {
+ pub fn new() -> TokenStream {
+ if nightly_works() {
+ TokenStream::Compiler(DeferredTokenStream::new(proc_macro::TokenStream::new()))
+ } else {
+ TokenStream::Fallback(fallback::TokenStream::new())
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ match self {
+ TokenStream::Compiler(tts) => tts.is_empty(),
+ TokenStream::Fallback(tts) => tts.is_empty(),
+ }
+ }
+
+ fn unwrap_nightly(self) -> proc_macro::TokenStream {
+ match self {
+ TokenStream::Compiler(s) => s.into_token_stream(),
+ TokenStream::Fallback(_) => mismatch(),
+ }
+ }
+
+ fn unwrap_stable(self) -> fallback::TokenStream {
+ match self {
+ TokenStream::Compiler(_) => mismatch(),
+ TokenStream::Fallback(s) => s,
+ }
+ }
+}
+
+impl FromStr for TokenStream {
+ type Err = LexError;
+
+ fn from_str(src: &str) -> Result<TokenStream, LexError> {
+ if nightly_works() {
+ Ok(TokenStream::Compiler(DeferredTokenStream::new(
+ src.parse()?,
+ )))
+ } else {
+ Ok(TokenStream::Fallback(src.parse()?))
+ }
+ }
+}
+
+impl fmt::Display for TokenStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ TokenStream::Compiler(tts) => tts.clone().into_token_stream().fmt(f),
+ TokenStream::Fallback(tts) => tts.fmt(f),
+ }
+ }
+}
+
+impl From<proc_macro::TokenStream> for TokenStream {
+ fn from(inner: proc_macro::TokenStream) -> TokenStream {
+ TokenStream::Compiler(DeferredTokenStream::new(inner))
+ }
+}
+
+impl From<TokenStream> for proc_macro::TokenStream {
+ fn from(inner: TokenStream) -> proc_macro::TokenStream {
+ match inner {
+ TokenStream::Compiler(inner) => inner.into_token_stream(),
+ TokenStream::Fallback(inner) => inner.to_string().parse().unwrap(),
+ }
+ }
+}
+
+impl From<fallback::TokenStream> for TokenStream {
+ fn from(inner: fallback::TokenStream) -> TokenStream {
+ TokenStream::Fallback(inner)
+ }
+}
+
+// Assumes nightly_works().
+fn into_compiler_token(token: TokenTree) -> proc_macro::TokenTree {
+ match token {
+ TokenTree::Group(tt) => tt.inner.unwrap_nightly().into(),
+ TokenTree::Punct(tt) => {
+ let spacing = match tt.spacing() {
+ Spacing::Joint => proc_macro::Spacing::Joint,
+ Spacing::Alone => proc_macro::Spacing::Alone,
+ };
+ let mut op = proc_macro::Punct::new(tt.as_char(), spacing);
+ op.set_span(tt.span().inner.unwrap_nightly());
+ op.into()
+ }
+ TokenTree::Ident(tt) => tt.inner.unwrap_nightly().into(),
+ TokenTree::Literal(tt) => tt.inner.unwrap_nightly().into(),
+ }
+}
+
+impl From<TokenTree> for TokenStream {
+ fn from(token: TokenTree) -> TokenStream {
+ if nightly_works() {
+ TokenStream::Compiler(DeferredTokenStream::new(into_compiler_token(token).into()))
+ } else {
+ TokenStream::Fallback(token.into())
+ }
+ }
+}
+
+impl iter::FromIterator<TokenTree> for TokenStream {
+ fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
+ if nightly_works() {
+ TokenStream::Compiler(DeferredTokenStream::new(
+ trees.into_iter().map(into_compiler_token).collect(),
+ ))
+ } else {
+ TokenStream::Fallback(trees.into_iter().collect())
+ }
+ }
+}
+
+impl iter::FromIterator<TokenStream> for TokenStream {
+ fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
+ let mut streams = streams.into_iter();
+ match streams.next() {
+ Some(TokenStream::Compiler(mut first)) => {
+ first.evaluate_now();
+ first.stream.extend(streams.map(|s| match s {
+ TokenStream::Compiler(s) => s.into_token_stream(),
+ TokenStream::Fallback(_) => mismatch(),
+ }));
+ TokenStream::Compiler(first)
+ }
+ Some(TokenStream::Fallback(mut first)) => {
+ first.extend(streams.map(|s| match s {
+ TokenStream::Fallback(s) => s,
+ TokenStream::Compiler(_) => mismatch(),
+ }));
+ TokenStream::Fallback(first)
+ }
+ None => TokenStream::new(),
+ }
+ }
+}
+
+impl Extend<TokenTree> for TokenStream {
+ fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) {
+ match self {
+ TokenStream::Compiler(tts) => {
+ // Here is the reason for DeferredTokenStream.
+ tts.extra
+ .extend(streams.into_iter().map(into_compiler_token));
+ }
+ TokenStream::Fallback(tts) => tts.extend(streams),
+ }
+ }
+}
+
+impl Extend<TokenStream> for TokenStream {
+ fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
+ match self {
+ TokenStream::Compiler(tts) => {
+ tts.evaluate_now();
+ tts.stream
+ .extend(streams.into_iter().map(|stream| stream.unwrap_nightly()));
+ }
+ TokenStream::Fallback(tts) => {
+ tts.extend(streams.into_iter().map(|stream| stream.unwrap_stable()));
+ }
+ }
+ }
+}
+
+impl fmt::Debug for TokenStream {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ TokenStream::Compiler(tts) => tts.clone().into_token_stream().fmt(f),
+ TokenStream::Fallback(tts) => tts.fmt(f),
+ }
+ }
+}
+
+impl From<proc_macro::LexError> for LexError {
+ fn from(e: proc_macro::LexError) -> LexError {
+ LexError::Compiler(e)
+ }
+}
+
+impl From<fallback::LexError> for LexError {
+ fn from(e: fallback::LexError) -> LexError {
+ LexError::Fallback(e)
+ }
+}
+
+impl fmt::Debug for LexError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ LexError::Compiler(e) => e.fmt(f),
+ LexError::Fallback(e) => e.fmt(f),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub enum TokenTreeIter {
+ Compiler(proc_macro::token_stream::IntoIter),
+ Fallback(fallback::TokenTreeIter),
+}
+
+impl IntoIterator for TokenStream {
+ type Item = TokenTree;
+ type IntoIter = TokenTreeIter;
+
+ fn into_iter(self) -> TokenTreeIter {
+ match self {
+ TokenStream::Compiler(tts) => {
+ TokenTreeIter::Compiler(tts.into_token_stream().into_iter())
+ }
+ TokenStream::Fallback(tts) => TokenTreeIter::Fallback(tts.into_iter()),
+ }
+ }
+}
+
+impl Iterator for TokenTreeIter {
+ type Item = TokenTree;
+
+ fn next(&mut self) -> Option<TokenTree> {
+ let token = match self {
+ TokenTreeIter::Compiler(iter) => iter.next()?,
+ TokenTreeIter::Fallback(iter) => return iter.next(),
+ };
+ Some(match token {
+ proc_macro::TokenTree::Group(tt) => crate::Group::_new(Group::Compiler(tt)).into(),
+ proc_macro::TokenTree::Punct(tt) => {
+ let spacing = match tt.spacing() {
+ proc_macro::Spacing::Joint => Spacing::Joint,
+ proc_macro::Spacing::Alone => Spacing::Alone,
+ };
+ let mut o = Punct::new(tt.as_char(), spacing);
+ o.set_span(crate::Span::_new(Span::Compiler(tt.span())));
+ o.into()
+ }
+ proc_macro::TokenTree::Ident(s) => crate::Ident::_new(Ident::Compiler(s)).into(),
+ proc_macro::TokenTree::Literal(l) => crate::Literal::_new(Literal::Compiler(l)).into(),
+ })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ match self {
+ TokenTreeIter::Compiler(tts) => tts.size_hint(),
+ TokenTreeIter::Fallback(tts) => tts.size_hint(),
+ }
+ }
+}
+
+impl fmt::Debug for TokenTreeIter {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("TokenTreeIter").finish()
+ }
+}
+
+#[derive(Clone, PartialEq, Eq)]
+#[cfg(super_unstable)]
+pub enum SourceFile {
+ Compiler(proc_macro::SourceFile),
+ Fallback(fallback::SourceFile),
+}
+
+#[cfg(super_unstable)]
+impl SourceFile {
+ fn nightly(sf: proc_macro::SourceFile) -> Self {
+ SourceFile::Compiler(sf)
+ }
+
+ /// Get the path to this source file as a string.
+ pub fn path(&self) -> PathBuf {
+ match self {
+ SourceFile::Compiler(a) => a.path(),
+ SourceFile::Fallback(a) => a.path(),
+ }
+ }
+
+ pub fn is_real(&self) -> bool {
+ match self {
+ SourceFile::Compiler(a) => a.is_real(),
+ SourceFile::Fallback(a) => a.is_real(),
+ }
+ }
+}
+
+#[cfg(super_unstable)]
+impl fmt::Debug for SourceFile {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ SourceFile::Compiler(a) => a.fmt(f),
+ SourceFile::Fallback(a) => a.fmt(f),
+ }
+ }
+}
+
+#[cfg(any(super_unstable, feature = "span-locations"))]
+pub struct LineColumn {
+ pub line: usize,
+ pub column: usize,
+}
+
+#[derive(Copy, Clone)]
+pub enum Span {
+ Compiler(proc_macro::Span),
+ Fallback(fallback::Span),
+}
+
+impl Span {
+ pub fn call_site() -> Span {
+ if nightly_works() {
+ Span::Compiler(proc_macro::Span::call_site())
+ } else {
+ Span::Fallback(fallback::Span::call_site())
+ }
+ }
+
+ #[cfg(super_unstable)]
+ pub fn def_site() -> Span {
+ if nightly_works() {
+ Span::Compiler(proc_macro::Span::def_site())
+ } else {
+ Span::Fallback(fallback::Span::def_site())
+ }
+ }
+
+ #[cfg(super_unstable)]
+ pub fn resolved_at(&self, other: Span) -> Span {
+ match (self, other) {
+ (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.resolved_at(b)),
+ (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.resolved_at(b)),
+ _ => mismatch(),
+ }
+ }
+
+ #[cfg(super_unstable)]
+ pub fn located_at(&self, other: Span) -> Span {
+ match (self, other) {
+ (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.located_at(b)),
+ (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.located_at(b)),
+ _ => mismatch(),
+ }
+ }
+
+ pub fn unwrap(self) -> proc_macro::Span {
+ match self {
+ Span::Compiler(s) => s,
+ Span::Fallback(_) => panic!("proc_macro::Span is only available in procedural macros"),
+ }
+ }
+
+ #[cfg(super_unstable)]
+ pub fn source_file(&self) -> SourceFile {
+ match self {
+ Span::Compiler(s) => SourceFile::nightly(s.source_file()),
+ Span::Fallback(s) => SourceFile::Fallback(s.source_file()),
+ }
+ }
+
+ #[cfg(any(super_unstable, feature = "span-locations"))]
+ pub fn start(&self) -> LineColumn {
+ match self {
+ #[cfg(proc_macro_span)]
+ Span::Compiler(s) => {
+ let proc_macro::LineColumn { line, column } = s.start();
+ LineColumn { line, column }
+ }
+ #[cfg(not(proc_macro_span))]
+ Span::Compiler(_) => LineColumn { line: 0, column: 0 },
+ Span::Fallback(s) => {
+ let fallback::LineColumn { line, column } = s.start();
+ LineColumn { line, column }
+ }
+ }
+ }
+
+ #[cfg(any(super_unstable, feature = "span-locations"))]
+ pub fn end(&self) -> LineColumn {
+ match self {
+ #[cfg(proc_macro_span)]
+ Span::Compiler(s) => {
+ let proc_macro::LineColumn { line, column } = s.end();
+ LineColumn { line, column }
+ }
+ #[cfg(not(proc_macro_span))]
+ Span::Compiler(_) => LineColumn { line: 0, column: 0 },
+ Span::Fallback(s) => {
+ let fallback::LineColumn { line, column } = s.end();
+ LineColumn { line, column }
+ }
+ }
+ }
+
+ pub fn join(&self, other: Span) -> Option<Span> {
+ let ret = match (self, other) {
+ #[cfg(proc_macro_span)]
+ (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.join(b)?),
+ (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.join(b)?),
+ _ => return None,
+ };
+ Some(ret)
+ }
+
+ #[cfg(super_unstable)]
+ pub fn eq(&self, other: &Span) -> bool {
+ match (self, other) {
+ (Span::Compiler(a), Span::Compiler(b)) => a.eq(b),
+ (Span::Fallback(a), Span::Fallback(b)) => a.eq(b),
+ _ => false,
+ }
+ }
+
+ fn unwrap_nightly(self) -> proc_macro::Span {
+ match self {
+ Span::Compiler(s) => s,
+ Span::Fallback(_) => mismatch(),
+ }
+ }
+}
+
+impl From<proc_macro::Span> for crate::Span {
+ fn from(proc_span: proc_macro::Span) -> crate::Span {
+ crate::Span::_new(Span::Compiler(proc_span))
+ }
+}
+
+impl From<fallback::Span> for Span {
+ fn from(inner: fallback::Span) -> Span {
+ Span::Fallback(inner)
+ }
+}
+
+impl fmt::Debug for Span {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Span::Compiler(s) => s.fmt(f),
+ Span::Fallback(s) => s.fmt(f),
+ }
+ }
+}
+
+pub fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) {
+ match span {
+ Span::Compiler(s) => {
+ debug.field("span", &s);
+ }
+ Span::Fallback(s) => fallback::debug_span_field_if_nontrivial(debug, s),
+ }
+}
+
+#[derive(Clone)]
+pub enum Group {
+ Compiler(proc_macro::Group),
+ Fallback(fallback::Group),
+}
+
+impl Group {
+ pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
+ match stream {
+ TokenStream::Compiler(tts) => {
+ let delimiter = match delimiter {
+ Delimiter::Parenthesis => proc_macro::Delimiter::Parenthesis,
+ Delimiter::Bracket => proc_macro::Delimiter::Bracket,
+ Delimiter::Brace => proc_macro::Delimiter::Brace,
+ Delimiter::None => proc_macro::Delimiter::None,
+ };
+ Group::Compiler(proc_macro::Group::new(delimiter, tts.into_token_stream()))
+ }
+ TokenStream::Fallback(stream) => {
+ Group::Fallback(fallback::Group::new(delimiter, stream))
+ }
+ }
+ }
+
+ pub fn delimiter(&self) -> Delimiter {
+ match self {
+ Group::Compiler(g) => match g.delimiter() {
+ proc_macro::Delimiter::Parenthesis => Delimiter::Parenthesis,
+ proc_macro::Delimiter::Bracket => Delimiter::Bracket,
+ proc_macro::Delimiter::Brace => Delimiter::Brace,
+ proc_macro::Delimiter::None => Delimiter::None,
+ },
+ Group::Fallback(g) => g.delimiter(),
+ }
+ }
+
+ pub fn stream(&self) -> TokenStream {
+ match self {
+ Group::Compiler(g) => TokenStream::Compiler(DeferredTokenStream::new(g.stream())),
+ Group::Fallback(g) => TokenStream::Fallback(g.stream()),
+ }
+ }
+
+ pub fn span(&self) -> Span {
+ match self {
+ Group::Compiler(g) => Span::Compiler(g.span()),
+ Group::Fallback(g) => Span::Fallback(g.span()),
+ }
+ }
+
+ pub fn span_open(&self) -> Span {
+ match self {
+ #[cfg(proc_macro_span)]
+ Group::Compiler(g) => Span::Compiler(g.span_open()),
+ #[cfg(not(proc_macro_span))]
+ Group::Compiler(g) => Span::Compiler(g.span()),
+ Group::Fallback(g) => Span::Fallback(g.span_open()),
+ }
+ }
+
+ pub fn span_close(&self) -> Span {
+ match self {
+ #[cfg(proc_macro_span)]
+ Group::Compiler(g) => Span::Compiler(g.span_close()),
+ #[cfg(not(proc_macro_span))]
+ Group::Compiler(g) => Span::Compiler(g.span()),
+ Group::Fallback(g) => Span::Fallback(g.span_close()),
+ }
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ match (self, span) {
+ (Group::Compiler(g), Span::Compiler(s)) => g.set_span(s),
+ (Group::Fallback(g), Span::Fallback(s)) => g.set_span(s),
+ _ => mismatch(),
+ }
+ }
+
+ fn unwrap_nightly(self) -> proc_macro::Group {
+ match self {
+ Group::Compiler(g) => g,
+ Group::Fallback(_) => mismatch(),
+ }
+ }
+}
+
+impl From<fallback::Group> for Group {
+ fn from(g: fallback::Group) -> Self {
+ Group::Fallback(g)
+ }
+}
+
+impl fmt::Display for Group {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Group::Compiler(group) => group.fmt(formatter),
+ Group::Fallback(group) => group.fmt(formatter),
+ }
+ }
+}
+
+impl fmt::Debug for Group {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Group::Compiler(group) => group.fmt(formatter),
+ Group::Fallback(group) => group.fmt(formatter),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub enum Ident {
+ Compiler(proc_macro::Ident),
+ Fallback(fallback::Ident),
+}
+
+impl Ident {
+ pub fn new(string: &str, span: Span) -> Ident {
+ match span {
+ Span::Compiler(s) => Ident::Compiler(proc_macro::Ident::new(string, s)),
+ Span::Fallback(s) => Ident::Fallback(fallback::Ident::new(string, s)),
+ }
+ }
+
+ pub fn new_raw(string: &str, span: Span) -> Ident {
+ match span {
+ Span::Compiler(s) => {
+ let p: proc_macro::TokenStream = string.parse().unwrap();
+ let ident = match p.into_iter().next() {
+ Some(proc_macro::TokenTree::Ident(mut i)) => {
+ i.set_span(s);
+ i
+ }
+ _ => panic!(),
+ };
+ Ident::Compiler(ident)
+ }
+ Span::Fallback(s) => Ident::Fallback(fallback::Ident::new_raw(string, s)),
+ }
+ }
+
+ pub fn span(&self) -> Span {
+ match self {
+ Ident::Compiler(t) => Span::Compiler(t.span()),
+ Ident::Fallback(t) => Span::Fallback(t.span()),
+ }
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ match (self, span) {
+ (Ident::Compiler(t), Span::Compiler(s)) => t.set_span(s),
+ (Ident::Fallback(t), Span::Fallback(s)) => t.set_span(s),
+ _ => mismatch(),
+ }
+ }
+
+ fn unwrap_nightly(self) -> proc_macro::Ident {
+ match self {
+ Ident::Compiler(s) => s,
+ Ident::Fallback(_) => mismatch(),
+ }
+ }
+}
+
+impl PartialEq for Ident {
+ fn eq(&self, other: &Ident) -> bool {
+ match (self, other) {
+ (Ident::Compiler(t), Ident::Compiler(o)) => t.to_string() == o.to_string(),
+ (Ident::Fallback(t), Ident::Fallback(o)) => t == o,
+ _ => mismatch(),
+ }
+ }
+}
+
+impl<T> PartialEq<T> for Ident
+where
+ T: ?Sized + AsRef<str>,
+{
+ fn eq(&self, other: &T) -> bool {
+ let other = other.as_ref();
+ match self {
+ Ident::Compiler(t) => t.to_string() == other,
+ Ident::Fallback(t) => t == other,
+ }
+ }
+}
+
+impl fmt::Display for Ident {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Ident::Compiler(t) => t.fmt(f),
+ Ident::Fallback(t) => t.fmt(f),
+ }
+ }
+}
+
+impl fmt::Debug for Ident {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Ident::Compiler(t) => t.fmt(f),
+ Ident::Fallback(t) => t.fmt(f),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub enum Literal {
+ Compiler(proc_macro::Literal),
+ Fallback(fallback::Literal),
+}
+
+macro_rules! suffixed_numbers {
+ ($($name:ident => $kind:ident,)*) => ($(
+ pub fn $name(n: $kind) -> Literal {
+ if nightly_works() {
+ Literal::Compiler(proc_macro::Literal::$name(n))
+ } else {
+ Literal::Fallback(fallback::Literal::$name(n))
+ }
+ }
+ )*)
+}
+
+macro_rules! unsuffixed_integers {
+ ($($name:ident => $kind:ident,)*) => ($(
+ pub fn $name(n: $kind) -> Literal {
+ if nightly_works() {
+ Literal::Compiler(proc_macro::Literal::$name(n))
+ } else {
+ Literal::Fallback(fallback::Literal::$name(n))
+ }
+ }
+ )*)
+}
+
+impl Literal {
+ suffixed_numbers! {
+ u8_suffixed => u8,
+ u16_suffixed => u16,
+ u32_suffixed => u32,
+ u64_suffixed => u64,
+ u128_suffixed => u128,
+ usize_suffixed => usize,
+ i8_suffixed => i8,
+ i16_suffixed => i16,
+ i32_suffixed => i32,
+ i64_suffixed => i64,
+ i128_suffixed => i128,
+ isize_suffixed => isize,
+
+ f32_suffixed => f32,
+ f64_suffixed => f64,
+ }
+
+ unsuffixed_integers! {
+ u8_unsuffixed => u8,
+ u16_unsuffixed => u16,
+ u32_unsuffixed => u32,
+ u64_unsuffixed => u64,
+ u128_unsuffixed => u128,
+ usize_unsuffixed => usize,
+ i8_unsuffixed => i8,
+ i16_unsuffixed => i16,
+ i32_unsuffixed => i32,
+ i64_unsuffixed => i64,
+ i128_unsuffixed => i128,
+ isize_unsuffixed => isize,
+ }
+
+ pub fn f32_unsuffixed(f: f32) -> Literal {
+ if nightly_works() {
+ Literal::Compiler(proc_macro::Literal::f32_unsuffixed(f))
+ } else {
+ Literal::Fallback(fallback::Literal::f32_unsuffixed(f))
+ }
+ }
+
+ pub fn f64_unsuffixed(f: f64) -> Literal {
+ if nightly_works() {
+ Literal::Compiler(proc_macro::Literal::f64_unsuffixed(f))
+ } else {
+ Literal::Fallback(fallback::Literal::f64_unsuffixed(f))
+ }
+ }
+
+ pub fn string(t: &str) -> Literal {
+ if nightly_works() {
+ Literal::Compiler(proc_macro::Literal::string(t))
+ } else {
+ Literal::Fallback(fallback::Literal::string(t))
+ }
+ }
+
+ pub fn character(t: char) -> Literal {
+ if nightly_works() {
+ Literal::Compiler(proc_macro::Literal::character(t))
+ } else {
+ Literal::Fallback(fallback::Literal::character(t))
+ }
+ }
+
+ pub fn byte_string(bytes: &[u8]) -> Literal {
+ if nightly_works() {
+ Literal::Compiler(proc_macro::Literal::byte_string(bytes))
+ } else {
+ Literal::Fallback(fallback::Literal::byte_string(bytes))
+ }
+ }
+
+ pub fn span(&self) -> Span {
+ match self {
+ Literal::Compiler(lit) => Span::Compiler(lit.span()),
+ Literal::Fallback(lit) => Span::Fallback(lit.span()),
+ }
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ match (self, span) {
+ (Literal::Compiler(lit), Span::Compiler(s)) => lit.set_span(s),
+ (Literal::Fallback(lit), Span::Fallback(s)) => lit.set_span(s),
+ _ => mismatch(),
+ }
+ }
+
+ pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
+ match self {
+ #[cfg(proc_macro_span)]
+ Literal::Compiler(lit) => lit.subspan(range).map(Span::Compiler),
+ #[cfg(not(proc_macro_span))]
+ Literal::Compiler(_lit) => None,
+ Literal::Fallback(lit) => lit.subspan(range).map(Span::Fallback),
+ }
+ }
+
+ fn unwrap_nightly(self) -> proc_macro::Literal {
+ match self {
+ Literal::Compiler(s) => s,
+ Literal::Fallback(_) => mismatch(),
+ }
+ }
+}
+
+impl From<fallback::Literal> for Literal {
+ fn from(s: fallback::Literal) -> Literal {
+ Literal::Fallback(s)
+ }
+}
+
+impl fmt::Display for Literal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Literal::Compiler(t) => t.fmt(f),
+ Literal::Fallback(t) => t.fmt(f),
+ }
+ }
+}
+
+impl fmt::Debug for Literal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Literal::Compiler(t) => t.fmt(f),
+ Literal::Fallback(t) => t.fmt(f),
+ }
+ }
+}
diff --git a/proc-macro2/tests/features.rs b/proc-macro2/tests/features.rs
new file mode 100644
index 0000000..073f6e6
--- /dev/null
+++ b/proc-macro2/tests/features.rs
@@ -0,0 +1,8 @@
+#[test]
+#[ignore]
+fn make_sure_no_proc_macro() {
+ assert!(
+ !cfg!(feature = "proc-macro"),
+ "still compiled with proc_macro?"
+ );
+}
diff --git a/proc-macro2/tests/marker.rs b/proc-macro2/tests/marker.rs
new file mode 100644
index 0000000..7af2539
--- /dev/null
+++ b/proc-macro2/tests/marker.rs
@@ -0,0 +1,59 @@
+use proc_macro2::*;
+
+macro_rules! assert_impl {
+ ($ty:ident is $($marker:ident) and +) => {
+ #[test]
+ #[allow(non_snake_case)]
+ fn $ty() {
+ fn assert_implemented<T: $($marker +)+>() {}
+ assert_implemented::<$ty>();
+ }
+ };
+
+ ($ty:ident is not $($marker:ident) or +) => {
+ #[test]
+ #[allow(non_snake_case)]
+ fn $ty() {
+ $(
+ {
+ // Implemented for types that implement $marker.
+ trait IsNotImplemented {
+ fn assert_not_implemented() {}
+ }
+ impl<T: $marker> IsNotImplemented for T {}
+
+ // Implemented for the type being tested.
+ trait IsImplemented {
+ fn assert_not_implemented() {}
+ }
+ impl IsImplemented for $ty {}
+
+ // If $ty does not implement $marker, there is no ambiguity
+ // in the following trait method call.
+ <$ty>::assert_not_implemented();
+ }
+ )+
+ }
+ };
+}
+
+assert_impl!(Delimiter is Send and Sync);
+assert_impl!(Spacing is Send and Sync);
+
+assert_impl!(Group is not Send or Sync);
+assert_impl!(Ident is not Send or Sync);
+assert_impl!(LexError is not Send or Sync);
+assert_impl!(Literal is not Send or Sync);
+assert_impl!(Punct is not Send or Sync);
+assert_impl!(Span is not Send or Sync);
+assert_impl!(TokenStream is not Send or Sync);
+assert_impl!(TokenTree is not Send or Sync);
+
+#[cfg(procmacro2_semver_exempt)]
+mod semver_exempt {
+ use super::*;
+
+ assert_impl!(LineColumn is Send and Sync);
+
+ assert_impl!(SourceFile is not Send or Sync);
+}
diff --git a/proc-macro2/tests/test.rs b/proc-macro2/tests/test.rs
new file mode 100644
index 0000000..7528388
--- /dev/null
+++ b/proc-macro2/tests/test.rs
@@ -0,0 +1,466 @@
+use std::str::{self, FromStr};
+
+use proc_macro2::{Ident, Literal, Spacing, Span, TokenStream, TokenTree};
+
+#[test]
+fn idents() {
+ assert_eq!(
+ Ident::new("String", Span::call_site()).to_string(),
+ "String"
+ );
+ assert_eq!(Ident::new("fn", Span::call_site()).to_string(), "fn");
+ assert_eq!(Ident::new("_", Span::call_site()).to_string(), "_");
+}
+
+#[test]
+#[cfg(procmacro2_semver_exempt)]
+fn raw_idents() {
+ assert_eq!(
+ Ident::new_raw("String", Span::call_site()).to_string(),
+ "r#String"
+ );
+ assert_eq!(Ident::new_raw("fn", Span::call_site()).to_string(), "r#fn");
+ assert_eq!(Ident::new_raw("_", Span::call_site()).to_string(), "r#_");
+}
+
+#[test]
+#[should_panic(expected = "Ident is not allowed to be empty; use Option<Ident>")]
+fn ident_empty() {
+ Ident::new("", Span::call_site());
+}
+
+#[test]
+#[should_panic(expected = "Ident cannot be a number; use Literal instead")]
+fn ident_number() {
+ Ident::new("255", Span::call_site());
+}
+
+#[test]
+#[should_panic(expected = "\"a#\" is not a valid Ident")]
+fn ident_invalid() {
+ Ident::new("a#", Span::call_site());
+}
+
+#[test]
+#[should_panic(expected = "not a valid Ident")]
+fn raw_ident_empty() {
+ Ident::new("r#", Span::call_site());
+}
+
+#[test]
+#[should_panic(expected = "not a valid Ident")]
+fn raw_ident_number() {
+ Ident::new("r#255", Span::call_site());
+}
+
+#[test]
+#[should_panic(expected = "\"r#a#\" is not a valid Ident")]
+fn raw_ident_invalid() {
+ Ident::new("r#a#", Span::call_site());
+}
+
+#[test]
+#[should_panic(expected = "not a valid Ident")]
+fn lifetime_empty() {
+ Ident::new("'", Span::call_site());
+}
+
+#[test]
+#[should_panic(expected = "not a valid Ident")]
+fn lifetime_number() {
+ Ident::new("'255", Span::call_site());
+}
+
+#[test]
+#[should_panic(expected = r#""\'a#" is not a valid Ident"#)]
+fn lifetime_invalid() {
+ Ident::new("'a#", Span::call_site());
+}
+
+#[test]
+fn literal_string() {
+ assert_eq!(Literal::string("foo").to_string(), "\"foo\"");
+ assert_eq!(Literal::string("\"").to_string(), "\"\\\"\"");
+ assert_eq!(Literal::string("didn't").to_string(), "\"didn't\"");
+}
+
+#[test]
+fn literal_character() {
+ assert_eq!(Literal::character('x').to_string(), "'x'");
+ assert_eq!(Literal::character('\'').to_string(), "'\\''");
+ assert_eq!(Literal::character('"').to_string(), "'\"'");
+}
+
+#[test]
+fn literal_float() {
+ assert_eq!(Literal::f32_unsuffixed(10.0).to_string(), "10.0");
+}
+
+#[test]
+fn literal_suffix() {
+ fn token_count(p: &str) -> usize {
+ p.parse::<TokenStream>().unwrap().into_iter().count()
+ }
+
+ assert_eq!(token_count("999u256"), 1);
+ assert_eq!(token_count("999r#u256"), 3);
+ assert_eq!(token_count("1."), 1);
+ assert_eq!(token_count("1.f32"), 3);
+ assert_eq!(token_count("1.0_0"), 1);
+ assert_eq!(token_count("1._0"), 3);
+ assert_eq!(token_count("1._m"), 3);
+ assert_eq!(token_count("\"\"s"), 1);
+}
+
+#[test]
+fn roundtrip() {
+ fn roundtrip(p: &str) {
+ println!("parse: {}", p);
+ let s = p.parse::<TokenStream>().unwrap().to_string();
+ println!("first: {}", s);
+ let s2 = s.to_string().parse::<TokenStream>().unwrap().to_string();
+ assert_eq!(s, s2);
+ }
+ roundtrip("a");
+ roundtrip("<<");
+ roundtrip("<<=");
+ roundtrip(
+ "
+ 1
+ 1.0
+ 1f32
+ 2f64
+ 1usize
+ 4isize
+ 4e10
+ 1_000
+ 1_0i32
+ 8u8
+ 9
+ 0
+ 0xffffffffffffffffffffffffffffffff
+ 1x
+ 1u80
+ 1f320
+ ",
+ );
+ roundtrip("'a");
+ roundtrip("'_");
+ roundtrip("'static");
+ roundtrip("'\\u{10__FFFF}'");
+ roundtrip("\"\\u{10_F0FF__}foo\\u{1_0_0_0__}\"");
+}
+
+#[test]
+fn fail() {
+ fn fail(p: &str) {
+ if let Ok(s) = p.parse::<TokenStream>() {
+ panic!("should have failed to parse: {}\n{:#?}", p, s);
+ }
+ }
+ fail("' static");
+ fail("r#1");
+ fail("r#_");
+}
+
+#[cfg(span_locations)]
+#[test]
+fn span_test() {
+ use proc_macro2::TokenTree;
+
+ fn check_spans(p: &str, mut lines: &[(usize, usize, usize, usize)]) {
+ let ts = p.parse::<TokenStream>().unwrap();
+ check_spans_internal(ts, &mut lines);
+ }
+
+ fn check_spans_internal(ts: TokenStream, lines: &mut &[(usize, usize, usize, usize)]) {
+ for i in ts {
+ if let Some((&(sline, scol, eline, ecol), rest)) = lines.split_first() {
+ *lines = rest;
+
+ let start = i.span().start();
+ assert_eq!(start.line, sline, "sline did not match for {}", i);
+ assert_eq!(start.column, scol, "scol did not match for {}", i);
+
+ let end = i.span().end();
+ assert_eq!(end.line, eline, "eline did not match for {}", i);
+ assert_eq!(end.column, ecol, "ecol did not match for {}", i);
+
+ match i {
+ TokenTree::Group(ref g) => {
+ check_spans_internal(g.stream().clone(), lines);
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+
+ check_spans(
+ "\
+/// This is a document comment
+testing 123
+{
+ testing 234
+}",
+ &[
+ (1, 0, 1, 30), // #
+ (1, 0, 1, 30), // [ ... ]
+ (1, 0, 1, 30), // doc
+ (1, 0, 1, 30), // =
+ (1, 0, 1, 30), // "This is..."
+ (2, 0, 2, 7), // testing
+ (2, 8, 2, 11), // 123
+ (3, 0, 5, 1), // { ... }
+ (4, 2, 4, 9), // testing
+ (4, 10, 4, 13), // 234
+ ],
+ );
+}
+
+#[cfg(procmacro2_semver_exempt)]
+#[cfg(not(nightly))]
+#[test]
+fn default_span() {
+ let start = Span::call_site().start();
+ assert_eq!(start.line, 1);
+ assert_eq!(start.column, 0);
+ let end = Span::call_site().end();
+ assert_eq!(end.line, 1);
+ assert_eq!(end.column, 0);
+ let source_file = Span::call_site().source_file();
+ assert_eq!(source_file.path().to_string_lossy(), "<unspecified>");
+ assert!(!source_file.is_real());
+}
+
+#[cfg(procmacro2_semver_exempt)]
+#[test]
+fn span_join() {
+ let source1 = "aaa\nbbb"
+ .parse::<TokenStream>()
+ .unwrap()
+ .into_iter()
+ .collect::<Vec<_>>();
+ let source2 = "ccc\nddd"
+ .parse::<TokenStream>()
+ .unwrap()
+ .into_iter()
+ .collect::<Vec<_>>();
+
+ assert!(source1[0].span().source_file() != source2[0].span().source_file());
+ assert_eq!(
+ source1[0].span().source_file(),
+ source1[1].span().source_file()
+ );
+
+ let joined1 = source1[0].span().join(source1[1].span());
+ let joined2 = source1[0].span().join(source2[0].span());
+ assert!(joined1.is_some());
+ assert!(joined2.is_none());
+
+ let start = joined1.unwrap().start();
+ let end = joined1.unwrap().end();
+ assert_eq!(start.line, 1);
+ assert_eq!(start.column, 0);
+ assert_eq!(end.line, 2);
+ assert_eq!(end.column, 3);
+
+ assert_eq!(
+ joined1.unwrap().source_file(),
+ source1[0].span().source_file()
+ );
+}
+
+#[test]
+fn no_panic() {
+ let s = str::from_utf8(b"b\'\xc2\x86 \x00\x00\x00^\"").unwrap();
+ assert!(s.parse::<proc_macro2::TokenStream>().is_err());
+}
+
+#[test]
+fn tricky_doc_comment() {
+ let stream = "/**/".parse::<proc_macro2::TokenStream>().unwrap();
+ let tokens = stream.into_iter().collect::<Vec<_>>();
+ assert!(tokens.is_empty(), "not empty -- {:?}", tokens);
+
+ let stream = "/// doc".parse::<proc_macro2::TokenStream>().unwrap();
+ let tokens = stream.into_iter().collect::<Vec<_>>();
+ assert!(tokens.len() == 2, "not length 2 -- {:?}", tokens);
+ match tokens[0] {
+ proc_macro2::TokenTree::Punct(ref tt) => assert_eq!(tt.as_char(), '#'),
+ _ => panic!("wrong token {:?}", tokens[0]),
+ }
+ let mut tokens = match tokens[1] {
+ proc_macro2::TokenTree::Group(ref tt) => {
+ assert_eq!(tt.delimiter(), proc_macro2::Delimiter::Bracket);
+ tt.stream().into_iter()
+ }
+ _ => panic!("wrong token {:?}", tokens[0]),
+ };
+
+ match tokens.next().unwrap() {
+ proc_macro2::TokenTree::Ident(ref tt) => assert_eq!(tt.to_string(), "doc"),
+ t => panic!("wrong token {:?}", t),
+ }
+ match tokens.next().unwrap() {
+ proc_macro2::TokenTree::Punct(ref tt) => assert_eq!(tt.as_char(), '='),
+ t => panic!("wrong token {:?}", t),
+ }
+ match tokens.next().unwrap() {
+ proc_macro2::TokenTree::Literal(ref tt) => {
+ assert_eq!(tt.to_string(), "\" doc\"");
+ }
+ t => panic!("wrong token {:?}", t),
+ }
+ assert!(tokens.next().is_none());
+
+ let stream = "//! doc".parse::<proc_macro2::TokenStream>().unwrap();
+ let tokens = stream.into_iter().collect::<Vec<_>>();
+ assert!(tokens.len() == 3, "not length 3 -- {:?}", tokens);
+}
+
+#[test]
+fn op_before_comment() {
+ let mut tts = TokenStream::from_str("~// comment").unwrap().into_iter();
+ match tts.next().unwrap() {
+ TokenTree::Punct(tt) => {
+ assert_eq!(tt.as_char(), '~');
+ assert_eq!(tt.spacing(), Spacing::Alone);
+ }
+ wrong => panic!("wrong token {:?}", wrong),
+ }
+}
+
+#[test]
+fn raw_identifier() {
+ let mut tts = TokenStream::from_str("r#dyn").unwrap().into_iter();
+ match tts.next().unwrap() {
+ TokenTree::Ident(raw) => assert_eq!("r#dyn", raw.to_string()),
+ wrong => panic!("wrong token {:?}", wrong),
+ }
+ assert!(tts.next().is_none());
+}
+
+#[test]
+fn test_debug_ident() {
+ let ident = Ident::new("proc_macro", Span::call_site());
+
+ #[cfg(not(procmacro2_semver_exempt))]
+ let expected = "Ident(proc_macro)";
+
+ #[cfg(procmacro2_semver_exempt)]
+ let expected = "Ident { sym: proc_macro, span: bytes(0..0) }";
+
+ assert_eq!(expected, format!("{:?}", ident));
+}
+
+#[test]
+fn test_debug_tokenstream() {
+ let tts = TokenStream::from_str("[a + 1]").unwrap();
+
+ #[cfg(not(procmacro2_semver_exempt))]
+ let expected = "\
+TokenStream [
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ sym: a,
+ },
+ Punct {
+ op: '+',
+ spacing: Alone,
+ },
+ Literal {
+ lit: 1,
+ },
+ ],
+ },
+]\
+ ";
+
+ #[cfg(not(procmacro2_semver_exempt))]
+ let expected_before_trailing_commas = "\
+TokenStream [
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ sym: a
+ },
+ Punct {
+ op: '+',
+ spacing: Alone
+ },
+ Literal {
+ lit: 1
+ }
+ ]
+ }
+]\
+ ";
+
+ #[cfg(procmacro2_semver_exempt)]
+ let expected = "\
+TokenStream [
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ sym: a,
+ span: bytes(2..3),
+ },
+ Punct {
+ op: '+',
+ spacing: Alone,
+ span: bytes(4..5),
+ },
+ Literal {
+ lit: 1,
+ span: bytes(6..7),
+ },
+ ],
+ span: bytes(1..8),
+ },
+]\
+ ";
+
+ #[cfg(procmacro2_semver_exempt)]
+ let expected_before_trailing_commas = "\
+TokenStream [
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ sym: a,
+ span: bytes(2..3)
+ },
+ Punct {
+ op: '+',
+ spacing: Alone,
+ span: bytes(4..5)
+ },
+ Literal {
+ lit: 1,
+ span: bytes(6..7)
+ }
+ ],
+ span: bytes(1..8)
+ }
+]\
+ ";
+
+ let actual = format!("{:#?}", tts);
+ if actual.ends_with(",\n]") {
+ assert_eq!(expected, actual);
+ } else {
+ assert_eq!(expected_before_trailing_commas, actual);
+ }
+}
+
+#[test]
+fn default_tokenstream_is_empty() {
+ let default_token_stream: TokenStream = Default::default();
+
+ assert!(default_token_stream.is_empty());
+}
diff --git a/quote/.gitignore b/quote/.gitignore
new file mode 100644
index 0000000..4fffb2f
--- /dev/null
+++ b/quote/.gitignore
@@ -0,0 +1,2 @@
+/target
+/Cargo.lock
diff --git a/quote/.travis.yml b/quote/.travis.yml
new file mode 100644
index 0000000..7182d9b
--- /dev/null
+++ b/quote/.travis.yml
@@ -0,0 +1,18 @@
+sudo: false
+
+language: rust
+
+rust:
+ - stable
+ - 1.31.0
+ - beta
+
+script:
+ - cargo test
+
+matrix:
+ include:
+ - rust: nightly
+ script:
+ - cargo test
+ - cargo update -Z minimal-versions && cargo build
diff --git a/quote/Cargo.toml b/quote/Cargo.toml
new file mode 100644
index 0000000..c052022
--- /dev/null
+++ b/quote/Cargo.toml
@@ -0,0 +1,32 @@
+[package]
+name = "quote"
+version = "1.0.2" # don't forget to update html_root_url, version in readme for breaking changes
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+license = "MIT OR Apache-2.0"
+description = "Quasi-quoting macro quote!(...)"
+repository = "https://github.com/dtolnay/quote"
+documentation = "https://docs.rs/quote/"
+keywords = ["syn"]
+categories = ["development-tools::procedural-macro-helpers"]
+readme = "README.md"
+include = ["Cargo.toml", "src/**/*.rs", "tests/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
+edition = "2018"
+
+[lib]
+name = "quote"
+
+[dependencies]
+proc-macro2 = { version = "1.0", default-features = false }
+
+[dev-dependencies]
+rustversion = "0.1"
+trybuild = "1.0"
+
+[features]
+default = ["proc-macro"]
+# Disabling the proc-macro feature removes the dynamic library dependency on
+# libproc_macro in the rustc compiler.
+proc-macro = ["proc-macro2/proc-macro"]
+
+[badges]
+travis-ci = { repository = "dtolnay/quote" }
diff --git a/quote/LICENSE-APACHE b/quote/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/quote/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/quote/LICENSE-MIT b/quote/LICENSE-MIT
new file mode 100644
index 0000000..40b8817
--- /dev/null
+++ b/quote/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2016 The Rust Project Developers
+
+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/quote/README.md b/quote/README.md
new file mode 100644
index 0000000..7c7f743
--- /dev/null
+++ b/quote/README.md
@@ -0,0 +1,237 @@
+Rust Quasi-Quoting
+==================
+
+[![Build Status](https://api.travis-ci.org/dtolnay/quote.svg?branch=master)](https://travis-ci.org/dtolnay/quote)
+[![Latest Version](https://img.shields.io/crates/v/quote.svg)](https://crates.io/crates/quote)
+[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/quote/)
+
+This crate provides the [`quote!`] macro for turning Rust syntax tree data
+structures into tokens of source code.
+
+[`quote!`]: https://docs.rs/quote/1.0/quote/macro.quote.html
+
+Procedural macros in Rust receive a stream of tokens as input, execute arbitrary
+Rust code to determine how to manipulate those tokens, and produce a stream of
+tokens to hand back to the compiler to compile into the caller's crate.
+Quasi-quoting is a solution to one piece of that &mdash; producing tokens to
+return to the compiler.
+
+The idea of quasi-quoting is that we write *code* that we treat as *data*.
+Within the `quote!` macro, we can write what looks like code to our text editor
+or IDE. We get all the benefits of the editor's brace matching, syntax
+highlighting, indentation, and maybe autocompletion. But rather than compiling
+that as code into the current crate, we can treat it as data, pass it around,
+mutate it, and eventually hand it back to the compiler as tokens to compile into
+the macro caller's crate.
+
+This crate is motivated by the procedural macro use case, but is a
+general-purpose Rust quasi-quoting library and is not specific to procedural
+macros.
+
+*Version requirement: Quote supports any compiler version back to Rust's very
+first support for procedural macros in Rust 1.15.0.*
+
+[*Release notes*](https://github.com/dtolnay/quote/releases)
+
+```toml
+[dependencies]
+quote = "1.0"
+```
+
+## Syntax
+
+The quote crate provides a [`quote!`] macro within which you can write Rust code
+that gets packaged into a [`TokenStream`] and can be treated as data. You should
+think of `TokenStream` as representing a fragment of Rust source code.
+
+[`TokenStream`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.TokenStream.html
+
+Within the `quote!` macro, interpolation is done with `#var`. Any type
+implementing the [`quote::ToTokens`] trait can be interpolated. This includes
+most Rust primitive types as well as most of the syntax tree types from [`syn`].
+
+[`quote::ToTokens`]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html
+[`syn`]: https://github.com/dtolnay/syn
+
+```rust
+let tokens = quote! {
+ struct SerializeWith #generics #where_clause {
+ value: &'a #field_ty,
+ phantom: core::marker::PhantomData<#item_ty>,
+ }
+
+ impl #generics serde::Serialize for SerializeWith #generics #where_clause {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ #path(self.value, serializer)
+ }
+ }
+
+ SerializeWith {
+ value: #value,
+ phantom: core::marker::PhantomData::<#item_ty>,
+ }
+};
+```
+
+## Repetition
+
+Repetition is done using `#(...)*` or `#(...),*` similar to `macro_rules!`. This
+iterates through the elements of any variable interpolated within the repetition
+and inserts a copy of the repetition body for each one. The variables in an
+interpolation may be anything that implements `IntoIterator`, including `Vec` or
+a pre-existing iterator.
+
+- `#(#var)*` — no separators
+- `#(#var),*` — the character before the asterisk is used as a separator
+- `#( struct #var; )*` — the repetition can contain other things
+- `#( #k => println!("{}", #v), )*` — even multiple interpolations
+
+Note that there is a difference between `#(#var ,)*` and `#(#var),*`—the latter
+does not produce a trailing comma. This matches the behavior of delimiters in
+`macro_rules!`.
+
+## Returning tokens to the compiler
+
+The `quote!` macro evaluates to an expression of type
+`proc_macro2::TokenStream`. Meanwhile Rust procedural macros are expected to
+return the type `proc_macro::TokenStream`.
+
+The difference between the two types is that `proc_macro` types are entirely
+specific to procedural macros and cannot ever exist in code outside of a
+procedural macro, while `proc_macro2` types may exist anywhere including tests
+and non-macro code like main.rs and build.rs. This is why even the procedural
+macro ecosystem is largely built around `proc_macro2`, because that ensures the
+libraries are unit testable and accessible in non-macro contexts.
+
+There is a [`From`]-conversion in both directions so returning the output of
+`quote!` from a procedural macro usually looks like `tokens.into()` or
+`proc_macro::TokenStream::from(tokens)`.
+
+[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
+
+## Examples
+
+### Combining quoted fragments
+
+Usually you don't end up constructing an entire final `TokenStream` in one
+piece. Different parts may come from different helper functions. The tokens
+produced by `quote!` themselves implement `ToTokens` and so can be interpolated
+into later `quote!` invocations to build up a final result.
+
+```rust
+let type_definition = quote! {...};
+let methods = quote! {...};
+
+let tokens = quote! {
+ #type_definition
+ #methods
+};
+```
+
+### Constructing identifiers
+
+Suppose we have an identifier `ident` which came from somewhere in a macro
+input and we need to modify it in some way for the macro output. Let's consider
+prepending the identifier with an underscore.
+
+Simply interpolating the identifier next to an underscore will not have the
+behavior of concatenating them. The underscore and the identifier will continue
+to be two separate tokens as if you had written `_ x`.
+
+```rust
+// incorrect
+quote! {
+ let mut _#ident = 0;
+}
+```
+
+The solution is to build a new identifier token with the correct value. As this
+is such a common case, the `format_ident!` macro provides a convenient utility
+for doing so correctly.
+
+```rust
+let varname = format_ident!("_{}", ident);
+quote! {
+ let mut #varname = 0;
+}
+```
+
+Alternatively, the APIs provided by Syn and proc-macro2 can be used to directly
+build the identifier. This is roughly equivalent to the above, but will not
+handle `ident` being a raw identifier.
+
+```rust
+let concatenated = format!("_{}", ident);
+let varname = syn::Ident::new(&concatenated, ident.span());
+quote! {
+ let mut #varname = 0;
+}
+```
+
+### Making method calls
+
+Let's say our macro requires some type specified in the macro input to have a
+constructor called `new`. We have the type in a variable called `field_type` of
+type `syn::Type` and want to invoke the constructor.
+
+```rust
+// incorrect
+quote! {
+ let value = #field_type::new();
+}
+```
+
+This works only sometimes. If `field_type` is `String`, the expanded code
+contains `String::new()` which is fine. But if `field_type` is something like
+`Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid syntax.
+Ordinarily in handwritten Rust we would write `Vec::<i32>::new()` but for macros
+often the following is more convenient.
+
+```rust
+quote! {
+ let value = <#field_type>::new();
+}
+```
+
+This expands to `<Vec<i32>>::new()` which behaves correctly.
+
+A similar pattern is appropriate for trait methods.
+
+```rust
+quote! {
+ let value = <#field_type as core::default::Default>::default();
+}
+```
+
+## Hygiene
+
+Any interpolated tokens preserve the `Span` information provided by their
+`ToTokens` implementation. Tokens that originate within a `quote!` invocation
+are spanned with [`Span::call_site()`].
+
+[`Span::call_site()`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html#method.call_site
+
+A different span can be provided explicitly through the [`quote_spanned!`]
+macro.
+
+[`quote_spanned!`]: https://docs.rs/quote/1.0/quote/macro.quote_spanned.html
+
+<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/quote/benches/bench.rs b/quote/benches/bench.rs
new file mode 100644
index 0000000..c76a638
--- /dev/null
+++ b/quote/benches/bench.rs
@@ -0,0 +1,193 @@
+#![feature(test)]
+#![recursion_limit = "512"]
+
+extern crate test;
+
+use quote::quote;
+use test::Bencher;
+
+#[bench]
+fn bench_impl(b: &mut Bencher) {
+ b.iter(|| {
+ quote! {
+ impl<'de> _serde::Deserialize<'de> for Response {
+ fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
+ where
+ __D: _serde::Deserializer<'de>,
+ {
+ #[allow(non_camel_case_types)]
+ enum __Field {
+ __field0,
+ __field1,
+ __ignore,
+ }
+ struct __FieldVisitor;
+ impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
+ type Value = __Field;
+ fn expecting(
+ &self,
+ __formatter: &mut _serde::export::Formatter,
+ ) -> _serde::export::fmt::Result {
+ _serde::export::Formatter::write_str(__formatter, "field identifier")
+ }
+ fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
+ where
+ __E: _serde::de::Error,
+ {
+ match __value {
+ 0u64 => _serde::export::Ok(__Field::__field0),
+ 1u64 => _serde::export::Ok(__Field::__field1),
+ _ => _serde::export::Err(_serde::de::Error::invalid_value(
+ _serde::de::Unexpected::Unsigned(__value),
+ &"field index 0 <= i < 2",
+ )),
+ }
+ }
+ fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E>
+ where
+ __E: _serde::de::Error,
+ {
+ match __value {
+ "id" => _serde::export::Ok(__Field::__field0),
+ "s" => _serde::export::Ok(__Field::__field1),
+ _ => _serde::export::Ok(__Field::__ignore),
+ }
+ }
+ fn visit_bytes<__E>(
+ self,
+ __value: &[u8],
+ ) -> _serde::export::Result<Self::Value, __E>
+ where
+ __E: _serde::de::Error,
+ {
+ match __value {
+ b"id" => _serde::export::Ok(__Field::__field0),
+ b"s" => _serde::export::Ok(__Field::__field1),
+ _ => _serde::export::Ok(__Field::__ignore),
+ }
+ }
+ }
+ impl<'de> _serde::Deserialize<'de> for __Field {
+ #[inline]
+ fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
+ where
+ __D: _serde::Deserializer<'de>,
+ {
+ _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
+ }
+ }
+ struct __Visitor<'de> {
+ marker: _serde::export::PhantomData<Response>,
+ lifetime: _serde::export::PhantomData<&'de ()>,
+ }
+ impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
+ type Value = Response;
+ fn expecting(
+ &self,
+ __formatter: &mut _serde::export::Formatter,
+ ) -> _serde::export::fmt::Result {
+ _serde::export::Formatter::write_str(__formatter, "struct Response")
+ }
+ #[inline]
+ fn visit_seq<__A>(
+ self,
+ mut __seq: __A,
+ ) -> _serde::export::Result<Self::Value, __A::Error>
+ where
+ __A: _serde::de::SeqAccess<'de>,
+ {
+ let __field0 =
+ match try!(_serde::de::SeqAccess::next_element::<u64>(&mut __seq)) {
+ _serde::export::Some(__value) => __value,
+ _serde::export::None => {
+ return _serde::export::Err(_serde::de::Error::invalid_length(
+ 0usize,
+ &"struct Response with 2 elements",
+ ));
+ }
+ };
+ let __field1 =
+ match try!(_serde::de::SeqAccess::next_element::<String>(&mut __seq)) {
+ _serde::export::Some(__value) => __value,
+ _serde::export::None => {
+ return _serde::export::Err(_serde::de::Error::invalid_length(
+ 1usize,
+ &"struct Response with 2 elements",
+ ));
+ }
+ };
+ _serde::export::Ok(Response {
+ id: __field0,
+ s: __field1,
+ })
+ }
+ #[inline]
+ fn visit_map<__A>(
+ self,
+ mut __map: __A,
+ ) -> _serde::export::Result<Self::Value, __A::Error>
+ where
+ __A: _serde::de::MapAccess<'de>,
+ {
+ let mut __field0: _serde::export::Option<u64> = _serde::export::None;
+ let mut __field1: _serde::export::Option<String> = _serde::export::None;
+ while let _serde::export::Some(__key) =
+ try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map))
+ {
+ match __key {
+ __Field::__field0 => {
+ if _serde::export::Option::is_some(&__field0) {
+ return _serde::export::Err(
+ <__A::Error as _serde::de::Error>::duplicate_field("id"),
+ );
+ }
+ __field0 = _serde::export::Some(
+ try!(_serde::de::MapAccess::next_value::<u64>(&mut __map)),
+ );
+ }
+ __Field::__field1 => {
+ if _serde::export::Option::is_some(&__field1) {
+ return _serde::export::Err(
+ <__A::Error as _serde::de::Error>::duplicate_field("s"),
+ );
+ }
+ __field1 = _serde::export::Some(
+ try!(_serde::de::MapAccess::next_value::<String>(&mut __map)),
+ );
+ }
+ _ => {
+ let _ = try!(_serde::de::MapAccess::next_value::<
+ _serde::de::IgnoredAny,
+ >(&mut __map));
+ }
+ }
+ }
+ let __field0 = match __field0 {
+ _serde::export::Some(__field0) => __field0,
+ _serde::export::None => try!(_serde::private::de::missing_field("id")),
+ };
+ let __field1 = match __field1 {
+ _serde::export::Some(__field1) => __field1,
+ _serde::export::None => try!(_serde::private::de::missing_field("s")),
+ };
+ _serde::export::Ok(Response {
+ id: __field0,
+ s: __field1,
+ })
+ }
+ }
+ const FIELDS: &'static [&'static str] = &["id", "s"];
+ _serde::Deserializer::deserialize_struct(
+ __deserializer,
+ "Response",
+ FIELDS,
+ __Visitor {
+ marker: _serde::export::PhantomData::<Response>,
+ lifetime: _serde::export::PhantomData,
+ },
+ )
+ }
+ }
+ }
+ });
+}
diff --git a/quote/src/ext.rs b/quote/src/ext.rs
new file mode 100644
index 0000000..9e9b4a5
--- /dev/null
+++ b/quote/src/ext.rs
@@ -0,0 +1,112 @@
+use super::ToTokens;
+
+use std::iter;
+
+use proc_macro2::{TokenStream, TokenTree};
+
+/// TokenStream extension trait with methods for appending tokens.
+///
+/// This trait is sealed and cannot be implemented outside of the `quote` crate.
+pub trait TokenStreamExt: private::Sealed {
+ /// For use by `ToTokens` implementations.
+ ///
+ /// Appends the token specified to this list of tokens.
+ fn append<U>(&mut self, token: U)
+ where
+ U: Into<TokenTree>;
+
+ /// For use by `ToTokens` implementations.
+ ///
+ /// ```
+ /// # use quote::{quote, TokenStreamExt, ToTokens};
+ /// # use proc_macro2::TokenStream;
+ /// #
+ /// struct X;
+ ///
+ /// impl ToTokens for X {
+ /// fn to_tokens(&self, tokens: &mut TokenStream) {
+ /// tokens.append_all(&[true, false]);
+ /// }
+ /// }
+ ///
+ /// let tokens = quote!(#X);
+ /// assert_eq!(tokens.to_string(), "true false");
+ /// ```
+ fn append_all<I>(&mut self, iter: I)
+ where
+ I: IntoIterator,
+ I::Item: ToTokens;
+
+ /// For use by `ToTokens` implementations.
+ ///
+ /// Appends all of the items in the iterator `I`, separated by the tokens
+ /// `U`.
+ fn append_separated<I, U>(&mut self, iter: I, op: U)
+ where
+ I: IntoIterator,
+ I::Item: ToTokens,
+ U: ToTokens;
+
+ /// For use by `ToTokens` implementations.
+ ///
+ /// Appends all tokens in the iterator `I`, appending `U` after each
+ /// element, including after the last element of the iterator.
+ fn append_terminated<I, U>(&mut self, iter: I, term: U)
+ where
+ I: IntoIterator,
+ I::Item: ToTokens,
+ U: ToTokens;
+}
+
+impl TokenStreamExt for TokenStream {
+ fn append<U>(&mut self, token: U)
+ where
+ U: Into<TokenTree>,
+ {
+ self.extend(iter::once(token.into()));
+ }
+
+ fn append_all<I>(&mut self, iter: I)
+ where
+ I: IntoIterator,
+ I::Item: ToTokens,
+ {
+ for token in iter {
+ token.to_tokens(self);
+ }
+ }
+
+ fn append_separated<I, U>(&mut self, iter: I, op: U)
+ where
+ I: IntoIterator,
+ I::Item: ToTokens,
+ U: ToTokens,
+ {
+ for (i, token) in iter.into_iter().enumerate() {
+ if i > 0 {
+ op.to_tokens(self);
+ }
+ token.to_tokens(self);
+ }
+ }
+
+ fn append_terminated<I, U>(&mut self, iter: I, term: U)
+ where
+ I: IntoIterator,
+ I::Item: ToTokens,
+ U: ToTokens,
+ {
+ for token in iter {
+ token.to_tokens(self);
+ term.to_tokens(self);
+ }
+ }
+}
+
+mod private {
+ use proc_macro2::TokenStream;
+
+ pub trait Sealed {}
+
+ impl Sealed for TokenStream {}
+}
diff --git a/quote/src/format.rs b/quote/src/format.rs
new file mode 100644
index 0000000..13c8811
--- /dev/null
+++ b/quote/src/format.rs
@@ -0,0 +1,164 @@
+/// Formatting macro for constructing `Ident`s.
+///
+/// <br>
+///
+/// # Syntax
+///
+/// Syntax is copied from the [`format!`] macro, supporting both positional and
+/// named arguments.
+///
+/// Only a limited set of formatting traits are supported. The current mapping
+/// of format types to traits is:
+///
+/// * `{}` ⇒ [`IdentFragment`]
+/// * `{:o}` ⇒ [`Octal`](`std::fmt::Octal`)
+/// * `{:x}` ⇒ [`LowerHex`](`std::fmt::LowerHex`)
+/// * `{:X}` ⇒ [`UpperHex`](`std::fmt::UpperHex`)
+/// * `{:b}` ⇒ [`Binary`](`std::fmt::Binary`)
+///
+/// See [`std::fmt`] for more information.
+///
+/// <br>
+///
+/// # IdentFragment
+///
+/// Unlike `format!`, this macro uses the [`IdentFragment`] formatting trait by
+/// default. This trait is like `Display`, with a few differences:
+///
+/// * `IdentFragment` is only implemented for a limited set of types, such as
+/// unsigned integers and strings.
+/// * [`Ident`] arguments will have their `r#` prefixes stripped, if present.
+///
+/// [`Ident`]: `proc_macro2::Ident`
+///
+/// <br>
+///
+/// # Hygiene
+///
+/// The [`Span`] of the first `Ident` argument is used as the span of the final
+/// identifier, falling back to [`Span::call_site`] when no identifiers are
+/// provided.
+///
+/// ```
+/// # use quote::format_ident;
+/// # let ident = format_ident!("Ident");
+/// // If `ident` is an Ident, the span of `my_ident` will be inherited from it.
+/// let my_ident = format_ident!("My{}{}", ident, "IsCool");
+/// assert_eq!(my_ident, "MyIdentIsCool");
+/// ```
+///
+/// Alternatively, the span can be overridden by passing the `span` named
+/// argument.
+///
+/// ```
+/// # use quote::format_ident;
+/// # const IGNORE_TOKENS: &'static str = stringify! {
+/// let my_span = /* ... */;
+/// # };
+/// # let my_span = proc_macro2::Span::call_site();
+/// format_ident!("MyIdent", span = my_span);
+/// ```
+///
+/// [`Span`]: `proc_macro2::Span`
+/// [`Span::call_site`]: `proc_macro2::Span::call_site`
+///
+/// <p><br></p>
+///
+/// # Panics
+///
+/// This method will panic if the resulting formatted string is not a valid
+/// identifier.
+///
+/// <br>
+///
+/// # Examples
+///
+/// Composing raw and non-raw identifiers:
+/// ```
+/// # use quote::format_ident;
+/// let my_ident = format_ident!("My{}", "Ident");
+/// assert_eq!(my_ident, "MyIdent");
+///
+/// let raw = format_ident!("r#Raw");
+/// assert_eq!(raw, "r#Raw");
+///
+/// let my_ident_raw = format_ident!("{}Is{}", my_ident, raw);
+/// assert_eq!(my_ident_raw, "MyIdentIsRaw");
+/// ```
+///
+/// Integer formatting options:
+/// ```
+/// # use quote::format_ident;
+/// let num: u32 = 10;
+///
+/// let decimal = format_ident!("Id_{}", num);
+/// assert_eq!(decimal, "Id_10");
+///
+/// let octal = format_ident!("Id_{:o}", num);
+/// assert_eq!(octal, "Id_12");
+///
+/// let binary = format_ident!("Id_{:b}", num);
+/// assert_eq!(binary, "Id_1010");
+///
+/// let lower_hex = format_ident!("Id_{:x}", num);
+/// assert_eq!(lower_hex, "Id_a");
+///
+/// let upper_hex = format_ident!("Id_{:X}", num);
+/// assert_eq!(upper_hex, "Id_A");
+/// ```
+#[macro_export]
+macro_rules! format_ident {
+ ($fmt:expr) => {
+ $crate::format_ident_impl!([
+ ::std::option::Option::None,
+ $fmt
+ ])
+ };
+
+ ($fmt:expr, $($rest:tt)*) => {
+ $crate::format_ident_impl!([
+ ::std::option::Option::None,
+ $fmt
+ ] $($rest)*)
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! format_ident_impl {
+ // Final state
+ ([$span:expr, $($fmt:tt)*]) => {
+ $crate::__rt::mk_ident(&format!($($fmt)*), $span)
+ };
+
+ // Span argument
+ ([$old:expr, $($fmt:tt)*] span = $span:expr) => {
+ $crate::format_ident_impl!([$old, $($fmt)*] span = $span,)
+ };
+ ([$old:expr, $($fmt:tt)*] span = $span:expr, $($rest:tt)*) => {
+ $crate::format_ident_impl!([
+ ::std::option::Option::Some::<$crate::__rt::Span>($span),
+ $($fmt)*
+ ] $($rest)*)
+ };
+
+ // Named argument
+ ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr) => {
+ $crate::format_ident_impl!([$span, $($fmt)*] $name = $arg,)
+ };
+ ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr, $($rest:tt)*) => {
+ match $crate::__rt::IdentFragmentAdapter(&$arg) {
+ arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, $name = arg] $($rest)*),
+ }
+ };
+
+ // Positional argument
+ ([$span:expr, $($fmt:tt)*] $arg:expr) => {
+ $crate::format_ident_impl!([$span, $($fmt)*] $arg,)
+ };
+ ([$span:expr, $($fmt:tt)*] $arg:expr, $($rest:tt)*) => {
+ match $crate::__rt::IdentFragmentAdapter(&$arg) {
+ arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, arg] $($rest)*),
+ }
+ };
+}
diff --git a/quote/src/ident_fragment.rs b/quote/src/ident_fragment.rs
new file mode 100644
index 0000000..09ead65
--- /dev/null
+++ b/quote/src/ident_fragment.rs
@@ -0,0 +1,72 @@
+use proc_macro2::{Ident, Span};
+use std::fmt;
+
+/// Specialized formatting trait used by `format_ident!`.
+///
+/// [`Ident`] arguments formatted using this trait will have their `r#` prefix
+/// stripped, if present.
+///
+/// See [`format_ident!`] for more information.
+pub trait IdentFragment {
+ /// Format this value as an identifier fragment.
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
+
+ /// Span associated with this `IdentFragment`.
+ ///
+ /// If non-`None`, may be inherited by formatted identifiers.
+ fn span(&self) -> Option<Span> {
+ None
+ }
+}
+
+impl<'a, T: IdentFragment + ?Sized> IdentFragment for &'a T {
+ fn span(&self) -> Option<Span> {
+ <T as IdentFragment>::span(*self)
+ }
+
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ IdentFragment::fmt(*self, f)
+ }
+}
+
+impl<'a, T: IdentFragment + ?Sized> IdentFragment for &'a mut T {
+ fn span(&self) -> Option<Span> {
+ <T as IdentFragment>::span(*self)
+ }
+
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ IdentFragment::fmt(*self, f)
+ }
+}
+
+impl IdentFragment for Ident {
+ fn span(&self) -> Option<Span> {
+ Some(self.span())
+ }
+
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let id = self.to_string();
+ if id.starts_with("r#") {
+ fmt::Display::fmt(&id[2..], f)
+ } else {
+ fmt::Display::fmt(&id[..], f)
+ }
+ }
+}
+
+// Limited set of types which this is implemented for, as we want to avoid types
+// which will often include non-identifier characters in their `Display` impl.
+macro_rules! ident_fragment_display {
+ ($($T:ty),*) => {
+ $(
+ impl IdentFragment for $T {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+ }
+ )*
+ }
+}
+
+ident_fragment_display!(bool, str, String);
+ident_fragment_display!(u8, u16, u32, u64, u128, usize);
diff --git a/quote/src/lib.rs b/quote/src/lib.rs
new file mode 100644
index 0000000..3341a16
--- /dev/null
+++ b/quote/src/lib.rs
@@ -0,0 +1,948 @@
+//! This crate provides the [`quote!`] macro for turning Rust syntax tree data
+//! structures into tokens of source code.
+//!
+//! [`quote!`]: macro.quote.html
+//!
+//! Procedural macros in Rust receive a stream of tokens as input, execute
+//! arbitrary Rust code to determine how to manipulate those tokens, and produce
+//! a stream of tokens to hand back to the compiler to compile into the caller's
+//! crate. Quasi-quoting is a solution to one piece of that &mdash; producing
+//! tokens to return to the compiler.
+//!
+//! The idea of quasi-quoting is that we write *code* that we treat as *data*.
+//! Within the `quote!` macro, we can write what looks like code to our text
+//! editor or IDE. We get all the benefits of the editor's brace matching,
+//! syntax highlighting, indentation, and maybe autocompletion. But rather than
+//! compiling that as code into the current crate, we can treat it as data, pass
+//! it around, mutate it, and eventually hand it back to the compiler as tokens
+//! to compile into the macro caller's crate.
+//!
+//! This crate is motivated by the procedural macro use case, but is a
+//! general-purpose Rust quasi-quoting library and is not specific to procedural
+//! macros.
+//!
+//! ```toml
+//! [dependencies]
+//! quote = "1.0"
+//! ```
+//!
+//! <br>
+//!
+//! # Example
+//!
+//! The following quasi-quoted block of code is something you might find in [a]
+//! procedural macro having to do with data structure serialization. The `#var`
+//! syntax performs interpolation of runtime variables into the quoted tokens.
+//! Check out the documentation of the [`quote!`] macro for more detail about
+//! the syntax. See also the [`quote_spanned!`] macro which is important for
+//! implementing hygienic procedural macros.
+//!
+//! [a]: https://serde.rs/
+//! [`quote_spanned!`]: macro.quote_spanned.html
+//!
+//! ```
+//! # use quote::quote;
+//! #
+//! # let generics = "";
+//! # let where_clause = "";
+//! # let field_ty = "";
+//! # let item_ty = "";
+//! # let path = "";
+//! # let value = "";
+//! #
+//! let tokens = quote! {
+//! struct SerializeWith #generics #where_clause {
+//! value: &'a #field_ty,
+//! phantom: core::marker::PhantomData<#item_ty>,
+//! }
+//!
+//! impl #generics serde::Serialize for SerializeWith #generics #where_clause {
+//! fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+//! where
+//! S: serde::Serializer,
+//! {
+//! #path(self.value, serializer)
+//! }
+//! }
+//!
+//! SerializeWith {
+//! value: #value,
+//! phantom: core::marker::PhantomData::<#item_ty>,
+//! }
+//! };
+//! ```
+
+// Quote types in rustdoc of other crates get linked to here.
+#![doc(html_root_url = "https://docs.rs/quote/1.0.2")]
+
+#[cfg(all(
+ not(all(target_arch = "wasm32", target_os = "unknown")),
+ feature = "proc-macro"
+))]
+extern crate proc_macro;
+
+mod ext;
+mod format;
+mod ident_fragment;
+mod to_tokens;
+
+// Not public API.
+#[doc(hidden)]
+#[path = "runtime.rs"]
+pub mod __rt;
+
+pub use crate::ext::TokenStreamExt;
+pub use crate::ident_fragment::IdentFragment;
+pub use crate::to_tokens::ToTokens;
+
+// Not public API.
+#[doc(hidden)]
+pub mod spanned;
+
+/// The whole point.
+///
+/// Performs variable interpolation against the input and produces it as
+/// [`proc_macro2::TokenStream`].
+///
+/// Note: for returning tokens to the compiler in a procedural macro, use
+/// `.into()` on the result to convert to [`proc_macro::TokenStream`].
+///
+/// [`TokenStream`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.TokenStream.html
+///
+/// <br>
+///
+/// # Interpolation
+///
+/// Variable interpolation is done with `#var` (similar to `$var` in
+/// `macro_rules!` macros). This grabs the `var` variable that is currently in
+/// scope and inserts it in that location in the output tokens. Any type
+/// implementing the [`ToTokens`] trait can be interpolated. This includes most
+/// Rust primitive types as well as most of the syntax tree types from the [Syn]
+/// crate.
+///
+/// [`ToTokens`]: trait.ToTokens.html
+/// [Syn]: https://github.com/dtolnay/syn
+///
+/// Repetition is done using `#(...)*` or `#(...),*` again similar to
+/// `macro_rules!`. This iterates through the elements of any variable
+/// interpolated within the repetition and inserts a copy of the repetition body
+/// for each one. The variables in an interpolation may be a `Vec`, slice,
+/// `BTreeSet`, or any `Iterator`.
+///
+/// - `#(#var)*` — no separators
+/// - `#(#var),*` — the character before the asterisk is used as a separator
+/// - `#( struct #var; )*` — the repetition can contain other tokens
+/// - `#( #k => println!("{}", #v), )*` — even multiple interpolations
+///
+/// <br>
+///
+/// # Hygiene
+///
+/// Any interpolated tokens preserve the `Span` information provided by their
+/// `ToTokens` implementation. Tokens that originate within the `quote!`
+/// invocation are spanned with [`Span::call_site()`].
+///
+/// [`Span::call_site()`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html#method.call_site
+///
+/// A different span can be provided through the [`quote_spanned!`] macro.
+///
+/// [`quote_spanned!`]: macro.quote_spanned.html
+///
+/// <br>
+///
+/// # Return type
+///
+/// The macro evaluates to an expression of type `proc_macro2::TokenStream`.
+/// Meanwhile Rust procedural macros are expected to return the type
+/// `proc_macro::TokenStream`.
+///
+/// The difference between the two types is that `proc_macro` types are entirely
+/// specific to procedural macros and cannot ever exist in code outside of a
+/// procedural macro, while `proc_macro2` types may exist anywhere including
+/// tests and non-macro code like main.rs and build.rs. This is why even the
+/// procedural macro ecosystem is largely built around `proc_macro2`, because
+/// that ensures the libraries are unit testable and accessible in non-macro
+/// contexts.
+///
+/// There is a [`From`]-conversion in both directions so returning the output of
+/// `quote!` from a procedural macro usually looks like `tokens.into()` or
+/// `proc_macro::TokenStream::from(tokens)`.
+///
+/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
+///
+/// <br>
+///
+/// # Examples
+///
+/// ### Procedural macro
+///
+/// The structure of a basic procedural macro is as follows. Refer to the [Syn]
+/// crate for further useful guidance on using `quote!` as part of a procedural
+/// macro.
+///
+/// [Syn]: https://github.com/dtolnay/syn
+///
+/// ```
+/// # #[cfg(any())]
+/// extern crate proc_macro;
+/// # extern crate proc_macro2;
+///
+/// # #[cfg(any())]
+/// use proc_macro::TokenStream;
+/// # use proc_macro2::TokenStream;
+/// use quote::quote;
+///
+/// # const IGNORE_TOKENS: &'static str = stringify! {
+/// #[proc_macro_derive(HeapSize)]
+/// # };
+/// pub fn derive_heap_size(input: TokenStream) -> TokenStream {
+/// // Parse the input and figure out what implementation to generate...
+/// # const IGNORE_TOKENS: &'static str = stringify! {
+/// let name = /* ... */;
+/// let expr = /* ... */;
+/// # };
+/// #
+/// # let name = 0;
+/// # let expr = 0;
+///
+/// let expanded = quote! {
+/// // The generated impl.
+/// impl heapsize::HeapSize for #name {
+/// fn heap_size_of_children(&self) -> usize {
+/// #expr
+/// }
+/// }
+/// };
+///
+/// // Hand the output tokens back to the compiler.
+/// TokenStream::from(expanded)
+/// }
+/// ```
+///
+/// <p><br></p>
+///
+/// ### Combining quoted fragments
+///
+/// Usually you don't end up constructing an entire final `TokenStream` in one
+/// piece. Different parts may come from different helper functions. The tokens
+/// produced by `quote!` themselves implement `ToTokens` and so can be
+/// interpolated into later `quote!` invocations to build up a final result.
+///
+/// ```
+/// # use quote::quote;
+/// #
+/// let type_definition = quote! {...};
+/// let methods = quote! {...};
+///
+/// let tokens = quote! {
+/// #type_definition
+/// #methods
+/// };
+/// ```
+///
+/// <p><br></p>
+///
+/// ### Constructing identifiers
+///
+/// Suppose we have an identifier `ident` which came from somewhere in a macro
+/// input and we need to modify it in some way for the macro output. Let's
+/// consider prepending the identifier with an underscore.
+///
+/// Simply interpolating the identifier next to an underscore will not have the
+/// behavior of concatenating them. The underscore and the identifier will
+/// continue to be two separate tokens as if you had written `_ x`.
+///
+/// ```
+/// # use proc_macro2::{self as syn, Span};
+/// # use quote::quote;
+/// #
+/// # let ident = syn::Ident::new("i", Span::call_site());
+/// #
+/// // incorrect
+/// quote! {
+/// let mut _#ident = 0;
+/// }
+/// # ;
+/// ```
+///
+/// The solution is to build a new identifier token with the correct value. As
+/// this is such a common case, the [`format_ident!`] macro provides a
+/// convenient utility for doing so correctly.
+///
+/// ```
+/// # use proc_macro2::{Ident, Span};
+/// # use quote::{format_ident, quote};
+/// #
+/// # let ident = Ident::new("i", Span::call_site());
+/// #
+/// let varname = format_ident!("_{}", ident);
+/// quote! {
+/// let mut #varname = 0;
+/// }
+/// # ;
+/// ```
+///
+/// Alternatively, the APIs provided by Syn and proc-macro2 can be used to
+/// directly build the identifier. This is roughly equivalent to the above, but
+/// will not handle `ident` being a raw identifier.
+///
+/// ```
+/// # use proc_macro2::{self as syn, Span};
+/// # use quote::quote;
+/// #
+/// # let ident = syn::Ident::new("i", Span::call_site());
+/// #
+/// let concatenated = format!("_{}", ident);
+/// let varname = syn::Ident::new(&concatenated, ident.span());
+/// quote! {
+/// let mut #varname = 0;
+/// }
+/// # ;
+/// ```
+///
+/// <p><br></p>
+///
+/// ### Making method calls
+///
+/// Let's say our macro requires some type specified in the macro input to have
+/// a constructor called `new`. We have the type in a variable called
+/// `field_type` of type `syn::Type` and want to invoke the constructor.
+///
+/// ```
+/// # use quote::quote;
+/// #
+/// # let field_type = quote!(...);
+/// #
+/// // incorrect
+/// quote! {
+/// let value = #field_type::new();
+/// }
+/// # ;
+/// ```
+///
+/// This works only sometimes. If `field_type` is `String`, the expanded code
+/// contains `String::new()` which is fine. But if `field_type` is something
+/// like `Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid
+/// syntax. Ordinarily in handwritten Rust we would write `Vec::<i32>::new()`
+/// but for macros often the following is more convenient.
+///
+/// ```
+/// # use quote::quote;
+/// #
+/// # let field_type = quote!(...);
+/// #
+/// quote! {
+/// let value = <#field_type>::new();
+/// }
+/// # ;
+/// ```
+///
+/// This expands to `<Vec<i32>>::new()` which behaves correctly.
+///
+/// A similar pattern is appropriate for trait methods.
+///
+/// ```
+/// # use quote::quote;
+/// #
+/// # let field_type = quote!(...);
+/// #
+/// quote! {
+/// let value = <#field_type as core::default::Default>::default();
+/// }
+/// # ;
+/// ```
+///
+/// <p><br></p>
+///
+/// ### Interpolating text inside of doc comments
+///
+/// Neither doc comments nor string literals get interpolation behavior in
+/// quote:
+///
+/// ```compile_fail
+/// quote! {
+/// /// try to interpolate: #ident
+/// ///
+/// /// ...
+/// }
+/// ```
+///
+/// ```compile_fail
+/// quote! {
+/// #[doc = "try to interpolate: #ident"]
+/// }
+/// ```
+///
+/// Macro calls in a doc attribute are not valid syntax:
+///
+/// ```compile_fail
+/// quote! {
+/// #[doc = concat!("try to interpolate: ", stringify!(#ident))]
+/// }
+/// ```
+///
+/// Instead the best way to build doc comments that involve variables is by
+/// formatting the doc string literal outside of quote.
+///
+/// ```rust
+/// # use proc_macro2::{Ident, Span};
+/// # use quote::quote;
+/// #
+/// # const IGNORE: &str = stringify! {
+/// let msg = format!(...);
+/// # };
+/// #
+/// # let ident = Ident::new("var", Span::call_site());
+/// # let msg = format!("try to interpolate: {}", ident);
+/// quote! {
+/// #[doc = #msg]
+/// ///
+/// /// ...
+/// }
+/// # ;
+/// ```
+///
+/// <p><br></p>
+///
+/// ### Indexing into a tuple struct
+///
+/// When interpolating indices of a tuple or tuple struct, we need them not to
+/// appears suffixed as integer literals by interpolating them as [`syn::Index`]
+/// instead.
+///
+/// [`syn::Index`]: https://docs.rs/syn/1.0/syn/struct.Index.html
+///
+/// ```compile_fail
+/// let i = 0usize..self.fields.len();
+///
+/// // expands to 0 + self.0usize.heap_size() + self.1usize.heap_size() + ...
+/// // which is not valid syntax
+/// quote! {
+/// 0 #( + self.#i.heap_size() )*
+/// }
+/// ```
+///
+/// ```
+/// # use proc_macro2::{Ident, TokenStream};
+/// # use quote::quote;
+/// #
+/// # mod syn {
+/// # use proc_macro2::{Literal, TokenStream};
+/// # use quote::{ToTokens, TokenStreamExt};
+/// #
+/// # pub struct Index(usize);
+/// #
+/// # impl From<usize> for Index {
+/// # fn from(i: usize) -> Self {
+/// # Index(i)
+/// # }
+/// # }
+/// #
+/// # impl ToTokens for Index {
+/// # fn to_tokens(&self, tokens: &mut TokenStream) {
+/// # tokens.append(Literal::usize_unsuffixed(self.0));
+/// # }
+/// # }
+/// # }
+/// #
+/// # struct Struct {
+/// # fields: Vec<Ident>,
+/// # }
+/// #
+/// # impl Struct {
+/// # fn example(&self) -> TokenStream {
+/// let i = (0..self.fields.len()).map(syn::Index::from);
+///
+/// // expands to 0 + self.0.heap_size() + self.1.heap_size() + ...
+/// quote! {
+/// 0 #( + self.#i.heap_size() )*
+/// }
+/// # }
+/// # }
+/// ```
+#[macro_export]
+macro_rules! quote {
+ ($($tt:tt)*) => {
+ $crate::quote_spanned!($crate::__rt::Span::call_site()=> $($tt)*)
+ };
+}
+
+/// Same as `quote!`, but applies a given span to all tokens originating within
+/// the macro invocation.
+///
+/// <br>
+///
+/// # Syntax
+///
+/// A span expression of type [`Span`], followed by `=>`, followed by the tokens
+/// to quote. The span expression should be brief &mdash; use a variable for
+/// anything more than a few characters. There should be no space before the
+/// `=>` token.
+///
+/// [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html
+///
+/// ```
+/// # use proc_macro2::Span;
+/// # use quote::quote_spanned;
+/// #
+/// # const IGNORE_TOKENS: &'static str = stringify! {
+/// let span = /* ... */;
+/// # };
+/// # let span = Span::call_site();
+/// # let init = 0;
+///
+/// // On one line, use parentheses.
+/// let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init)));
+///
+/// // On multiple lines, place the span at the top and use braces.
+/// let tokens = quote_spanned! {span=>
+/// Box::into_raw(Box::new(#init))
+/// };
+/// ```
+///
+/// The lack of space before the `=>` should look jarring to Rust programmers
+/// and this is intentional. The formatting is designed to be visibly
+/// off-balance and draw the eye a particular way, due to the span expression
+/// being evaluated in the context of the procedural macro and the remaining
+/// tokens being evaluated in the generated code.
+///
+/// <br>
+///
+/// # Hygiene
+///
+/// Any interpolated tokens preserve the `Span` information provided by their
+/// `ToTokens` implementation. Tokens that originate within the `quote_spanned!`
+/// invocation are spanned with the given span argument.
+///
+/// <br>
+///
+/// # Example
+///
+/// The following procedural macro code uses `quote_spanned!` to assert that a
+/// particular Rust type implements the [`Sync`] trait so that references can be
+/// safely shared between threads.
+///
+/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+///
+/// ```
+/// # use quote::{quote_spanned, TokenStreamExt, ToTokens};
+/// # use proc_macro2::{Span, TokenStream};
+/// #
+/// # struct Type;
+/// #
+/// # impl Type {
+/// # fn span(&self) -> Span {
+/// # Span::call_site()
+/// # }
+/// # }
+/// #
+/// # impl ToTokens for Type {
+/// # fn to_tokens(&self, _tokens: &mut TokenStream) {}
+/// # }
+/// #
+/// # let ty = Type;
+/// # let call_site = Span::call_site();
+/// #
+/// let ty_span = ty.span();
+/// let assert_sync = quote_spanned! {ty_span=>
+/// struct _AssertSync where #ty: Sync;
+/// };
+/// ```
+///
+/// If the assertion fails, the user will see an error like the following. The
+/// input span of their type is hightlighted in the error.
+///
+/// ```text
+/// error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
+/// --> src/main.rs:10:21
+/// |
+/// 10 | static ref PTR: *const () = &();
+/// | ^^^^^^^^^ `*const ()` cannot be shared between threads safely
+/// ```
+///
+/// In this example it is important for the where-clause to be spanned with the
+/// line/column information of the user's input type so that error messages are
+/// placed appropriately by the compiler.
+#[macro_export]
+macro_rules! quote_spanned {
+ ($span:expr=> $($tt:tt)*) => {{
+ let mut _s = $crate::__rt::TokenStream::new();
+ let _span: $crate::__rt::Span = $span;
+ $crate::quote_each_token!(_s _span $($tt)*);
+ _s
+ }};
+}
+
+// Extract the names of all #metavariables and pass them to the $call macro.
+//
+// in: pounded_var_names!(then!(...) a #b c #( #d )* #e)
+// out: then!(... b);
+// then!(... d);
+// then!(... e);
+#[macro_export]
+#[doc(hidden)]
+macro_rules! pounded_var_names {
+ ($call:ident! $extra:tt $($tts:tt)*) => {
+ $crate::pounded_var_names_with_context!($call! $extra
+ (@ $($tts)*)
+ ($($tts)* @)
+ )
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! pounded_var_names_with_context {
+ ($call:ident! $extra:tt ($($b1:tt)*) ($($curr:tt)*)) => {
+ $(
+ $crate::pounded_var_with_context!($call! $extra $b1 $curr);
+ )*
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! pounded_var_with_context {
+ ($call:ident! $extra:tt $b1:tt ( $($inner:tt)* )) => {
+ $crate::pounded_var_names!($call! $extra $($inner)*);
+ };
+
+ ($call:ident! $extra:tt $b1:tt [ $($inner:tt)* ]) => {
+ $crate::pounded_var_names!($call! $extra $($inner)*);
+ };
+
+ ($call:ident! $extra:tt $b1:tt { $($inner:tt)* }) => {
+ $crate::pounded_var_names!($call! $extra $($inner)*);
+ };
+
+ ($call:ident!($($extra:tt)*) # $var:ident) => {
+ $crate::$call!($($extra)* $var);
+ };
+
+ ($call:ident! $extra:tt $b1:tt $curr:tt) => {};
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_bind_into_iter {
+ ($has_iter:ident $var:ident) => {
+ // `mut` may be unused if $var occurs multiple times in the list.
+ #[allow(unused_mut)]
+ let (mut $var, i) = $var.quote_into_iter();
+ let $has_iter = $has_iter | i;
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_bind_next_or_break {
+ ($var:ident) => {
+ let $var = match $var.next() {
+ Some(_x) => $crate::__rt::RepInterp(_x),
+ None => break,
+ };
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_each_token {
+ ($tokens:ident $span:ident $($tts:tt)*) => {
+ $crate::quote_tokens_with_context!($tokens $span
+ (@ @ @ @ @ @ $($tts)*)
+ (@ @ @ @ @ $($tts)* @)
+ (@ @ @ @ $($tts)* @ @)
+ (@ @ @ $(($tts))* @ @ @)
+ (@ @ $($tts)* @ @ @ @)
+ (@ $($tts)* @ @ @ @ @)
+ ($($tts)* @ @ @ @ @ @)
+ );
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_tokens_with_context {
+ ($tokens:ident $span:ident
+ ($($b3:tt)*) ($($b2:tt)*) ($($b1:tt)*)
+ ($($curr:tt)*)
+ ($($a1:tt)*) ($($a2:tt)*) ($($a3:tt)*)
+ ) => {
+ $(
+ $crate::quote_token_with_context!($tokens $span $b3 $b2 $b1 $curr $a1 $a2 $a3);
+ )*
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_token_with_context {
+ ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {};
+
+ ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{
+ use $crate::__rt::ext::*;
+ let has_iter = $crate::__rt::ThereIsNoIteratorInRepetition;
+ $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*);
+ let _: $crate::__rt::HasIterator = has_iter;
+ // This is `while true` instead of `loop` because if there are no
+ // iterators used inside of this repetition then the body would not
+ // contain any `break`, so the compiler would emit unreachable code
+ // warnings on anything below the loop. We use has_iter to detect and
+ // fail to compile when there are no iterators, so here we just work
+ // around the unneeded extra warning.
+ while true {
+ $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
+ $crate::quote_each_token!($tokens $span $($inner)*);
+ }
+ }};
+ ($tokens:ident $span:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {};
+ ($tokens:ident $span:ident $b3:tt # ( $($inner:tt)* ) (*) $a1:tt $a2:tt $a3:tt) => {};
+
+ ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{
+ use $crate::__rt::ext::*;
+ let mut _i = 0usize;
+ let has_iter = $crate::__rt::ThereIsNoIteratorInRepetition;
+ $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*);
+ let _: $crate::__rt::HasIterator = has_iter;
+ while true {
+ $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
+ if _i > 0 {
+ $crate::quote_token!($tokens $span $sep);
+ }
+ _i += 1;
+ $crate::quote_each_token!($tokens $span $($inner)*);
+ }
+ }};
+ ($tokens:ident $span:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {};
+ ($tokens:ident $span:ident $b3:tt # ( $($inner:tt)* ) ($sep:tt) * $a2:tt $a3:tt) => {};
+ ($tokens:ident $span:ident # ( $($inner:tt)* ) * (*) $a1:tt $a2:tt $a3:tt) => {
+ // https://github.com/dtolnay/quote/issues/130
+ $crate::quote_token!($tokens $span *);
+ };
+ ($tokens:ident $span:ident # ( $($inner:tt)* ) $sep:tt (*) $a1:tt $a2:tt $a3:tt) => {};
+
+ ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) $var:ident $a2:tt $a3:tt) => {
+ $crate::ToTokens::to_tokens(&$var, &mut $tokens);
+ };
+ ($tokens:ident $span:ident $b3:tt $b2:tt # ($var:ident) $a1:tt $a2:tt $a3:tt) => {};
+ ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt ($curr:tt) $a1:tt $a2:tt $a3:tt) => {
+ $crate::quote_token!($tokens $span $curr);
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! quote_token {
+ ($tokens:ident $span:ident ( $($inner:tt)* )) => {
+ $tokens.extend({
+ let mut g = $crate::__rt::Group::new(
+ $crate::__rt::Delimiter::Parenthesis,
+ $crate::quote_spanned!($span=> $($inner)*),
+ );
+ g.set_span($span);
+ Some($crate::__rt::TokenTree::from(g))
+ });
+ };
+
+ ($tokens:ident $span:ident [ $($inner:tt)* ]) => {
+ $tokens.extend({
+ let mut g = $crate::__rt::Group::new(
+ $crate::__rt::Delimiter::Bracket,
+ $crate::quote_spanned!($span=> $($inner)*),
+ );
+ g.set_span($span);
+ Some($crate::__rt::TokenTree::from(g))
+ });
+ };
+
+ ($tokens:ident $span:ident { $($inner:tt)* }) => {
+ $tokens.extend({
+ let mut g = $crate::__rt::Group::new(
+ $crate::__rt::Delimiter::Brace,
+ $crate::quote_spanned!($span=> $($inner)*),
+ );
+ g.set_span($span);
+ Some($crate::__rt::TokenTree::from(g))
+ });
+ };
+
+ ($tokens:ident $span:ident +) => {
+ $crate::__rt::push_add(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident +=) => {
+ $crate::__rt::push_add_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident &) => {
+ $crate::__rt::push_and(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident &&) => {
+ $crate::__rt::push_and_and(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident &=) => {
+ $crate::__rt::push_and_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident @) => {
+ $crate::__rt::push_at(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident !) => {
+ $crate::__rt::push_bang(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ^) => {
+ $crate::__rt::push_caret(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ^=) => {
+ $crate::__rt::push_caret_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident :) => {
+ $crate::__rt::push_colon(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ::) => {
+ $crate::__rt::push_colon2(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ,) => {
+ $crate::__rt::push_comma(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident /) => {
+ $crate::__rt::push_div(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident /=) => {
+ $crate::__rt::push_div_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident .) => {
+ $crate::__rt::push_dot(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ..) => {
+ $crate::__rt::push_dot2(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ...) => {
+ $crate::__rt::push_dot3(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ..=) => {
+ $crate::__rt::push_dot_dot_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident =) => {
+ $crate::__rt::push_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ==) => {
+ $crate::__rt::push_eq_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident >=) => {
+ $crate::__rt::push_ge(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident >) => {
+ $crate::__rt::push_gt(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident <=) => {
+ $crate::__rt::push_le(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident <) => {
+ $crate::__rt::push_lt(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident *=) => {
+ $crate::__rt::push_mul_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident !=) => {
+ $crate::__rt::push_ne(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident |) => {
+ $crate::__rt::push_or(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident |=) => {
+ $crate::__rt::push_or_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ||) => {
+ $crate::__rt::push_or_or(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident #) => {
+ $crate::__rt::push_pound(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ?) => {
+ $crate::__rt::push_question(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ->) => {
+ $crate::__rt::push_rarrow(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident <-) => {
+ $crate::__rt::push_larrow(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident %) => {
+ $crate::__rt::push_rem(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident %=) => {
+ $crate::__rt::push_rem_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident =>) => {
+ $crate::__rt::push_fat_arrow(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident ;) => {
+ $crate::__rt::push_semi(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident <<) => {
+ $crate::__rt::push_shl(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident <<=) => {
+ $crate::__rt::push_shl_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident >>) => {
+ $crate::__rt::push_shr(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident >>=) => {
+ $crate::__rt::push_shr_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident *) => {
+ $crate::__rt::push_star(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident -) => {
+ $crate::__rt::push_sub(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident -=) => {
+ $crate::__rt::push_sub_eq(&mut $tokens, $span);
+ };
+
+ ($tokens:ident $span:ident $other:tt) => {
+ $crate::__rt::parse(&mut $tokens, $span, stringify!($other));
+ };
+}
diff --git a/quote/src/runtime.rs b/quote/src/runtime.rs
new file mode 100644
index 0000000..4a1c14c
--- /dev/null
+++ b/quote/src/runtime.rs
@@ -0,0 +1,373 @@
+use crate::{IdentFragment, ToTokens, TokenStreamExt};
+use std::fmt;
+use std::ops::BitOr;
+
+pub use proc_macro2::*;
+
+pub struct HasIterator; // True
+pub struct ThereIsNoIteratorInRepetition; // False
+
+impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
+ type Output = ThereIsNoIteratorInRepetition;
+ fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
+ ThereIsNoIteratorInRepetition
+ }
+}
+
+impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
+ type Output = HasIterator;
+ fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
+ HasIterator
+ }
+}
+
+impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
+ type Output = HasIterator;
+ fn bitor(self, _rhs: HasIterator) -> HasIterator {
+ HasIterator
+ }
+}
+
+impl BitOr<HasIterator> for HasIterator {
+ type Output = HasIterator;
+ fn bitor(self, _rhs: HasIterator) -> HasIterator {
+ HasIterator
+ }
+}
+
+/// Extension traits used by the implementation of `quote!`. These are defined
+/// in separate traits, rather than as a single trait due to ambiguity issues.
+///
+/// These traits expose a `quote_into_iter` method which should allow calling
+/// whichever impl happens to be applicable. Calling that method repeatedly on
+/// the returned value should be idempotent.
+pub mod ext {
+ use super::RepInterp;
+ use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
+ use crate::ToTokens;
+ use std::collections::btree_set::{self, BTreeSet};
+ use std::slice;
+
+ /// Extension trait providing the `quote_into_iter` method on iterators.
+ pub trait RepIteratorExt: Iterator + Sized {
+ fn quote_into_iter(self) -> (Self, HasIter) {
+ (self, HasIter)
+ }
+ }
+
+ impl<T: Iterator> RepIteratorExt for T {}
+
+ /// Extension trait providing the `quote_into_iter` method for
+ /// non-iterable types. These types interpolate the same value in each
+ /// iteration of the repetition.
+ pub trait RepToTokensExt {
+ /// Pretend to be an iterator for the purposes of `quote_into_iter`.
+ /// This allows repeated calls to `quote_into_iter` to continue
+ /// correctly returning DoesNotHaveIter.
+ fn next(&self) -> Option<&Self> {
+ Some(self)
+ }
+
+ fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) {
+ (self, DoesNotHaveIter)
+ }
+ }
+
+ impl<T: ToTokens + ?Sized> RepToTokensExt for T {}
+
+ /// Extension trait providing the `quote_into_iter` method for types that
+ /// can be referenced as an iterator.
+ pub trait RepAsIteratorExt<'q> {
+ type Iter: Iterator;
+
+ fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
+ }
+
+ impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a T {
+ type Iter = T::Iter;
+
+ fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+ <T as RepAsIteratorExt>::quote_into_iter(*self)
+ }
+ }
+
+ impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a mut T {
+ type Iter = T::Iter;
+
+ fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+ <T as RepAsIteratorExt>::quote_into_iter(*self)
+ }
+ }
+
+ impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
+ type Iter = slice::Iter<'q, T>;
+
+ fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+ (self.iter(), HasIter)
+ }
+ }
+
+ impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
+ type Iter = slice::Iter<'q, T>;
+
+ fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+ (self.iter(), HasIter)
+ }
+ }
+
+ impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
+ type Iter = btree_set::Iter<'q, T>;
+
+ fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+ (self.iter(), HasIter)
+ }
+ }
+
+ macro_rules! array_rep_slice {
+ ($($l:tt)*) => {
+ $(
+ impl<'q, T: 'q> RepAsIteratorExt<'q> for [T; $l] {
+ type Iter = slice::Iter<'q, T>;
+
+ fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+ (self.iter(), HasIter)
+ }
+ }
+ )*
+ }
+ }
+
+ array_rep_slice!(
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
+ );
+
+ impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
+ type Iter = T::Iter;
+
+ fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+ self.0.quote_into_iter()
+ }
+ }
+}
+
+// Helper type used within interpolations to allow for repeated binding names.
+// Implements the relevant traits, and exports a dummy `next()` method.
+#[derive(Copy, Clone)]
+pub struct RepInterp<T>(pub T);
+
+impl<T> RepInterp<T> {
+ // This method is intended to look like `Iterator::next`, and is called when
+ // a name is bound multiple times, as the previous binding will shadow the
+ // original `Iterator` object. This allows us to avoid advancing the
+ // iterator multiple times per iteration.
+ pub fn next(self) -> Option<T> {
+ Some(self.0)
+ }
+}
+
+impl<T: Iterator> Iterator for RepInterp<T> {
+ type Item = T::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+}
+
+impl<T: ToTokens> ToTokens for RepInterp<T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.0.to_tokens(tokens);
+ }
+}
+
+fn is_ident_start(c: u8) -> bool {
+ (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_'
+}
+
+fn is_ident_continue(c: u8) -> bool {
+ (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_' || (b'0' <= c && c <= b'9')
+}
+
+fn is_ident(token: &str) -> bool {
+ let mut iter = token.bytes();
+ let first_ok = iter.next().map(is_ident_start).unwrap_or(false);
+
+ first_ok && iter.all(is_ident_continue)
+}
+
+pub fn parse(tokens: &mut TokenStream, span: Span, s: &str) {
+ if is_ident(s) {
+ // Fast path, since idents are the most common token.
+ tokens.append(Ident::new(s, span));
+ } else {
+ let s: TokenStream = s.parse().expect("invalid token stream");
+ tokens.extend(s.into_iter().map(|mut t| {
+ t.set_span(span);
+ t
+ }));
+ }
+}
+
+macro_rules! push_punct {
+ ($name:ident $char1:tt) => {
+ pub fn $name(tokens: &mut TokenStream, span: Span) {
+ let mut punct = Punct::new($char1, Spacing::Alone);
+ punct.set_span(span);
+ tokens.append(punct);
+ }
+ };
+ ($name:ident $char1:tt $char2:tt) => {
+ pub fn $name(tokens: &mut TokenStream, span: Span) {
+ let mut punct = Punct::new($char1, Spacing::Joint);
+ punct.set_span(span);
+ tokens.append(punct);
+ let mut punct = Punct::new($char2, Spacing::Alone);
+ punct.set_span(span);
+ tokens.append(punct);
+ }
+ };
+ ($name:ident $char1:tt $char2:tt $char3:tt) => {
+ pub fn $name(tokens: &mut TokenStream, span: Span) {
+ let mut punct = Punct::new($char1, Spacing::Joint);
+ punct.set_span(span);
+ tokens.append(punct);
+ let mut punct = Punct::new($char2, Spacing::Joint);
+ punct.set_span(span);
+ tokens.append(punct);
+ let mut punct = Punct::new($char3, Spacing::Alone);
+ punct.set_span(span);
+ tokens.append(punct);
+ }
+ };
+}
+
+push_punct!(push_add '+');
+push_punct!(push_add_eq '+' '=');
+push_punct!(push_and '&');
+push_punct!(push_and_and '&' '&');
+push_punct!(push_and_eq '&' '=');
+push_punct!(push_at '@');
+push_punct!(push_bang '!');
+push_punct!(push_caret '^');
+push_punct!(push_caret_eq '^' '=');
+push_punct!(push_colon ':');
+push_punct!(push_colon2 ':' ':');
+push_punct!(push_comma ',');
+push_punct!(push_div '/');
+push_punct!(push_div_eq '/' '=');
+push_punct!(push_dot '.');
+push_punct!(push_dot2 '.' '.');
+push_punct!(push_dot3 '.' '.' '.');
+push_punct!(push_dot_dot_eq '.' '.' '=');
+push_punct!(push_eq '=');
+push_punct!(push_eq_eq '=' '=');
+push_punct!(push_ge '>' '=');
+push_punct!(push_gt '>');
+push_punct!(push_le '<' '=');
+push_punct!(push_lt '<');
+push_punct!(push_mul_eq '*' '=');
+push_punct!(push_ne '!' '=');
+push_punct!(push_or '|');
+push_punct!(push_or_eq '|' '=');
+push_punct!(push_or_or '|' '|');
+push_punct!(push_pound '#');
+push_punct!(push_question '?');
+push_punct!(push_rarrow '-' '>');
+push_punct!(push_larrow '<' '-');
+push_punct!(push_rem '%');
+push_punct!(push_rem_eq '%' '=');
+push_punct!(push_fat_arrow '=' '>');
+push_punct!(push_semi ';');
+push_punct!(push_shl '<' '<');
+push_punct!(push_shl_eq '<' '<' '=');
+push_punct!(push_shr '>' '>');
+push_punct!(push_shr_eq '>' '>' '=');
+push_punct!(push_star '*');
+push_punct!(push_sub '-');
+push_punct!(push_sub_eq '-' '=');
+
+// Helper method for constructing identifiers from the `format_ident!` macro,
+// handling `r#` prefixes.
+//
+// Directly parsing the input string may produce a valid identifier,
+// although the input string was invalid, due to ignored characters such as
+// whitespace and comments. Instead, we always create a non-raw identifier
+// to validate that the string is OK, and only parse again if needed.
+//
+// The `is_ident` method defined above is insufficient for validation, as it
+// will reject non-ASCII identifiers.
+pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
+ let span = span.unwrap_or_else(Span::call_site);
+
+ let is_raw = id.starts_with("r#");
+ let unraw = Ident::new(if is_raw { &id[2..] } else { id }, span);
+ if !is_raw {
+ return unraw;
+ }
+
+ // At this point, the identifier is raw, and the unraw-ed version of it was
+ // successfully converted into an identifier. Try to produce a valid raw
+ // identifier by running the `TokenStream` parser, and unwrapping the first
+ // token as an `Ident`.
+ //
+ // FIXME: When `Ident::new_raw` becomes stable, this method should be
+ // updated to call it when available.
+ match id.parse::<TokenStream>() {
+ Ok(ts) => {
+ let mut iter = ts.into_iter();
+ match (iter.next(), iter.next()) {
+ (Some(TokenTree::Ident(mut id)), None) => {
+ id.set_span(span);
+ id
+ }
+ _ => unreachable!("valid raw ident fails to parse"),
+ }
+ }
+ Err(_) => unreachable!("valid raw ident fails to parse"),
+ }
+}
+
+// Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!`
+// macro, and exposes span information from these fragments.
+//
+// This struct also has forwarding implementations of the formatting traits
+// `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within
+// `format_ident!`.
+#[derive(Copy, Clone)]
+pub struct IdentFragmentAdapter<T: IdentFragment>(pub T);
+
+impl<T: IdentFragment> IdentFragmentAdapter<T> {
+ pub fn span(&self) -> Option<Span> {
+ self.0.span()
+ }
+}
+
+impl<T: IdentFragment> fmt::Display for IdentFragmentAdapter<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ IdentFragment::fmt(&self.0, f)
+ }
+}
+
+impl<T: IdentFragment + fmt::Octal> fmt::Octal for IdentFragmentAdapter<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Octal::fmt(&self.0, f)
+ }
+}
+
+impl<T: IdentFragment + fmt::LowerHex> fmt::LowerHex for IdentFragmentAdapter<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::LowerHex::fmt(&self.0, f)
+ }
+}
+
+impl<T: IdentFragment + fmt::UpperHex> fmt::UpperHex for IdentFragmentAdapter<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::UpperHex::fmt(&self.0, f)
+ }
+}
+
+impl<T: IdentFragment + fmt::Binary> fmt::Binary for IdentFragmentAdapter<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Binary::fmt(&self.0, f)
+ }
+}
diff --git a/quote/src/spanned.rs b/quote/src/spanned.rs
new file mode 100644
index 0000000..55168bd
--- /dev/null
+++ b/quote/src/spanned.rs
@@ -0,0 +1,42 @@
+use crate::ToTokens;
+use proc_macro2::{Span, TokenStream};
+
+pub trait Spanned {
+ fn __span(&self) -> Span;
+}
+
+impl Spanned for Span {
+ fn __span(&self) -> Span {
+ *self
+ }
+}
+
+impl<T: ?Sized + ToTokens> Spanned for T {
+ fn __span(&self) -> Span {
+ join_spans(self.into_token_stream())
+ }
+}
+
+fn join_spans(tokens: TokenStream) -> Span {
+ let mut iter = tokens.into_iter().filter_map(|tt| {
+ // FIXME: This shouldn't be required, since optimally spans should
+ // never be invalid. This filter_map can probably be removed when
+ // https://github.com/rust-lang/rust/issues/43081 is resolved.
+ let span = tt.span();
+ let debug = format!("{:?}", span);
+ if debug.ends_with("bytes(0..0)") {
+ None
+ } else {
+ Some(span)
+ }
+ });
+
+ let first = match iter.next() {
+ Some(span) => span,
+ None => return Span::call_site(),
+ };
+
+ iter.fold(None, |_prev, next| Some(next))
+ .and_then(|last| first.join(last))
+ .unwrap_or(first)
+}
diff --git a/quote/src/to_tokens.rs b/quote/src/to_tokens.rs
new file mode 100644
index 0000000..7f98083
--- /dev/null
+++ b/quote/src/to_tokens.rs
@@ -0,0 +1,209 @@
+use super::TokenStreamExt;
+
+use std::borrow::Cow;
+use std::iter;
+use std::rc::Rc;
+
+use proc_macro2::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
+
+/// Types that can be interpolated inside a `quote!` invocation.
+///
+/// [`quote!`]: macro.quote.html
+pub trait ToTokens {
+ /// Write `self` to the given `TokenStream`.
+ ///
+ /// The token append methods provided by the [`TokenStreamExt`] extension
+ /// trait may be useful for implementing `ToTokens`.
+ ///
+ /// [`TokenStreamExt`]: trait.TokenStreamExt.html
+ ///
+ /// # Example
+ ///
+ /// Example implementation for a struct representing Rust paths like
+ /// `std::cmp::PartialEq`:
+ ///
+ /// ```
+ /// use proc_macro2::{TokenTree, Spacing, Span, Punct, TokenStream};
+ /// use quote::{TokenStreamExt, ToTokens};
+ ///
+ /// pub struct Path {
+ /// pub global: bool,
+ /// pub segments: Vec<PathSegment>,
+ /// }
+ ///
+ /// impl ToTokens for Path {
+ /// fn to_tokens(&self, tokens: &mut TokenStream) {
+ /// for (i, segment) in self.segments.iter().enumerate() {
+ /// if i > 0 || self.global {
+ /// // Double colon `::`
+ /// tokens.append(Punct::new(':', Spacing::Joint));
+ /// tokens.append(Punct::new(':', Spacing::Alone));
+ /// }
+ /// segment.to_tokens(tokens);
+ /// }
+ /// }
+ /// }
+ /// #
+ /// # pub struct PathSegment;
+ /// #
+ /// # impl ToTokens for PathSegment {
+ /// # fn to_tokens(&self, tokens: &mut TokenStream) {
+ /// # unimplemented!()
+ /// # }
+ /// # }
+ /// ```
+ fn to_tokens(&self, tokens: &mut TokenStream);
+
+ /// Convert `self` directly into a `TokenStream` object.
+ ///
+ /// This method is implicitly implemented using `to_tokens`, and acts as a
+ /// convenience method for consumers of the `ToTokens` trait.
+ fn to_token_stream(&self) -> TokenStream {
+ let mut tokens = TokenStream::new();
+ self.to_tokens(&mut tokens);
+ tokens
+ }
+
+ /// Convert `self` directly into a `TokenStream` object.
+ ///
+ /// This method is implicitly implemented using `to_tokens`, and acts as a
+ /// convenience method for consumers of the `ToTokens` trait.
+ fn into_token_stream(self) -> TokenStream
+ where
+ Self: Sized,
+ {
+ self.to_token_stream()
+ }
+}
+
+impl<'a, T: ?Sized + ToTokens> ToTokens for &'a T {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens);
+ }
+}
+
+impl<'a, T: ?Sized + ToTokens> ToTokens for &'a mut T {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens);
+ }
+}
+
+impl<'a, T: ?Sized + ToOwned + ToTokens> ToTokens for Cow<'a, T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens);
+ }
+}
+
+impl<T: ?Sized + ToTokens> ToTokens for Box<T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens);
+ }
+}
+
+impl<T: ?Sized + ToTokens> ToTokens for Rc<T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens);
+ }
+}
+
+impl<T: ToTokens> ToTokens for Option<T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if let Some(ref t) = *self {
+ t.to_tokens(tokens);
+ }
+ }
+}
+
+impl ToTokens for str {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(Literal::string(self));
+ }
+}
+
+impl ToTokens for String {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.as_str().to_tokens(tokens);
+ }
+}
+
+macro_rules! primitive {
+ ($($t:ident => $name:ident)*) => ($(
+ impl ToTokens for $t {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(Literal::$name(*self));
+ }
+ }
+ )*)
+}
+
+primitive! {
+ i8 => i8_suffixed
+ i16 => i16_suffixed
+ i32 => i32_suffixed
+ i64 => i64_suffixed
+ i128 => i128_suffixed
+ isize => isize_suffixed
+
+ u8 => u8_suffixed
+ u16 => u16_suffixed
+ u32 => u32_suffixed
+ u64 => u64_suffixed
+ u128 => u128_suffixed
+ usize => usize_suffixed
+
+ f32 => f32_suffixed
+ f64 => f64_suffixed
+}
+
+impl ToTokens for char {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(Literal::character(*self));
+ }
+}
+
+impl ToTokens for bool {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let word = if *self { "true" } else { "false" };
+ tokens.append(Ident::new(word, Span::call_site()));
+ }
+}
+
+impl ToTokens for Group {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(self.clone());
+ }
+}
+
+impl ToTokens for Ident {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(self.clone());
+ }
+}
+
+impl ToTokens for Punct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(self.clone());
+ }
+}
+
+impl ToTokens for Literal {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(self.clone());
+ }
+}
+
+impl ToTokens for TokenTree {
+ fn to_tokens(&self, dst: &mut TokenStream) {
+ dst.append(self.clone());
+ }
+}
+
+impl ToTokens for TokenStream {
+ fn to_tokens(&self, dst: &mut TokenStream) {
+ dst.extend(iter::once(self.clone()));
+ }
+
+ fn into_token_stream(self) -> TokenStream {
+ self
+ }
+}
diff --git a/quote/tests/compiletest.rs b/quote/tests/compiletest.rs
new file mode 100644
index 0000000..f9aea23
--- /dev/null
+++ b/quote/tests/compiletest.rs
@@ -0,0 +1,6 @@
+#[rustversion::attr(not(nightly), ignore)]
+#[test]
+fn ui() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/*.rs");
+}
diff --git a/quote/tests/test.rs b/quote/tests/test.rs
new file mode 100644
index 0000000..957d470
--- /dev/null
+++ b/quote/tests/test.rs
@@ -0,0 +1,429 @@
+#![cfg_attr(feature = "cargo-clippy", allow(blacklisted_name))]
+
+use std::borrow::Cow;
+use std::collections::BTreeSet;
+
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::{format_ident, quote, TokenStreamExt};
+
+struct X;
+
+impl quote::ToTokens for X {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(Ident::new("X", Span::call_site()));
+ }
+}
+
+#[test]
+fn test_quote_impl() {
+ let tokens = quote! {
+ impl<'a, T: ToTokens> ToTokens for &'a T {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ (**self).to_tokens(tokens)
+ }
+ }
+ };
+
+ let expected = concat!(
+ "impl < 'a , T : ToTokens > ToTokens for & 'a T { ",
+ "fn to_tokens ( & self , tokens : & mut TokenStream ) { ",
+ "( * * self ) . to_tokens ( tokens ) ",
+ "} ",
+ "}"
+ );
+
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_substitution() {
+ let x = X;
+ let tokens = quote!(#x <#x> (#x) [#x] {#x});
+
+ let expected = "X < X > ( X ) [ X ] { X }";
+
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_iter() {
+ let primes = &[X, X, X, X];
+
+ assert_eq!("X X X X", quote!(#(#primes)*).to_string());
+
+ assert_eq!("X , X , X , X ,", quote!(#(#primes,)*).to_string());
+
+ assert_eq!("X , X , X , X", quote!(#(#primes),*).to_string());
+}
+
+#[test]
+fn test_advanced() {
+ let generics = quote!( <'a, T> );
+
+ let where_clause = quote!( where T: Serialize );
+
+ let field_ty = quote!(String);
+
+ let item_ty = quote!(Cow<'a, str>);
+
+ let path = quote!(SomeTrait::serialize_with);
+
+ let value = quote!(self.x);
+
+ let tokens = quote! {
+ struct SerializeWith #generics #where_clause {
+ value: &'a #field_ty,
+ phantom: ::std::marker::PhantomData<#item_ty>,
+ }
+
+ impl #generics ::serde::Serialize for SerializeWith #generics #where_clause {
+ fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
+ where S: ::serde::Serializer
+ {
+ #path(self.value, s)
+ }
+ }
+
+ SerializeWith {
+ value: #value,
+ phantom: ::std::marker::PhantomData::<#item_ty>,
+ }
+ };
+
+ let expected = concat!(
+ "struct SerializeWith < 'a , T > where T : Serialize { ",
+ "value : & 'a String , ",
+ "phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , ",
+ "} ",
+ "impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { ",
+ "fn serialize < S > ( & self , s : & mut S ) -> Result < ( ) , S :: Error > ",
+ "where S : :: serde :: Serializer ",
+ "{ ",
+ "SomeTrait :: serialize_with ( self . value , s ) ",
+ "} ",
+ "} ",
+ "SerializeWith { ",
+ "value : self . x , ",
+ "phantom : :: std :: marker :: PhantomData :: < Cow < 'a , str > > , ",
+ "}"
+ );
+
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_integer() {
+ let ii8 = -1i8;
+ let ii16 = -1i16;
+ let ii32 = -1i32;
+ let ii64 = -1i64;
+ let ii128 = -1i128;
+ let iisize = -1isize;
+ let uu8 = 1u8;
+ let uu16 = 1u16;
+ let uu32 = 1u32;
+ let uu64 = 1u64;
+ let uu128 = 1u128;
+ let uusize = 1usize;
+
+ let tokens = quote! {
+ #ii8 #ii16 #ii32 #ii64 #ii128 #iisize
+ #uu8 #uu16 #uu32 #uu64 #uu128 #uusize
+ };
+ let expected = "-1i8 -1i16 -1i32 -1i64 -1i128 -1isize 1u8 1u16 1u32 1u64 1u128 1usize";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_floating() {
+ let e32 = 2.345f32;
+
+ let e64 = 2.345f64;
+
+ let tokens = quote! {
+ #e32
+ #e64
+ };
+ let expected = concat!("2.345f32 2.345f64");
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_char() {
+ let zero = '\0';
+ let pound = '#';
+ let quote = '"';
+ let apost = '\'';
+ let newline = '\n';
+ let heart = '\u{2764}';
+
+ let tokens = quote! {
+ #zero #pound #quote #apost #newline #heart
+ };
+ let expected = "'\\u{0}' '#' '\"' '\\'' '\\n' '\\u{2764}'";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_str() {
+ let s = "\0 a 'b \" c";
+ let tokens = quote!(#s);
+ let expected = "\"\\u{0} a 'b \\\" c\"";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_string() {
+ let s = "\0 a 'b \" c".to_string();
+ let tokens = quote!(#s);
+ let expected = "\"\\u{0} a 'b \\\" c\"";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_ident() {
+ let foo = Ident::new("Foo", Span::call_site());
+ let bar = Ident::new(&format!("Bar{}", 7), Span::call_site());
+ let tokens = quote!(struct #foo; enum #bar {});
+ let expected = "struct Foo ; enum Bar7 { }";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_duplicate() {
+ let ch = 'x';
+
+ let tokens = quote!(#ch #ch);
+
+ let expected = "'x' 'x'";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_fancy_repetition() {
+ let foo = vec!["a", "b"];
+ let bar = vec![true, false];
+
+ let tokens = quote! {
+ #(#foo: #bar),*
+ };
+
+ let expected = r#""a" : true , "b" : false"#;
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_nested_fancy_repetition() {
+ let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']];
+
+ let tokens = quote! {
+ #(
+ #(#nested)*
+ ),*
+ };
+
+ let expected = "'a' 'b' 'c' , 'x' 'y' 'z'";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_duplicate_name_repetition() {
+ let foo = &["a", "b"];
+
+ let tokens = quote! {
+ #(#foo: #foo),*
+ #(#foo: #foo),*
+ };
+
+ let expected = r#""a" : "a" , "b" : "b" "a" : "a" , "b" : "b""#;
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_duplicate_name_repetition_no_copy() {
+ let foo = vec!["a".to_owned(), "b".to_owned()];
+
+ let tokens = quote! {
+ #(#foo: #foo),*
+ };
+
+ let expected = r#""a" : "a" , "b" : "b""#;
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_btreeset_repetition() {
+ let mut set = BTreeSet::new();
+ set.insert("a".to_owned());
+ set.insert("b".to_owned());
+
+ let tokens = quote! {
+ #(#set: #set),*
+ };
+
+ let expected = r#""a" : "a" , "b" : "b""#;
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_variable_name_conflict() {
+ // The implementation of `#(...),*` uses the variable `_i` but it should be
+ // fine, if a little confusing when debugging.
+ let _i = vec!['a', 'b'];
+ let tokens = quote! { #(#_i),* };
+ let expected = "'a' , 'b'";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_nonrep_in_repetition() {
+ let rep = vec!["a", "b"];
+ let nonrep = "c";
+
+ let tokens = quote! {
+ #(#rep #rep : #nonrep #nonrep),*
+ };
+
+ let expected = r#""a" "a" : "c" "c" , "b" "b" : "c" "c""#;
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_empty_quote() {
+ let tokens = quote!();
+ assert_eq!("", tokens.to_string());
+}
+
+#[test]
+fn test_box_str() {
+ let b = "str".to_owned().into_boxed_str();
+ let tokens = quote! { #b };
+ assert_eq!("\"str\"", tokens.to_string());
+}
+
+#[test]
+fn test_cow() {
+ let owned: Cow<Ident> = Cow::Owned(Ident::new("owned", Span::call_site()));
+
+ let ident = Ident::new("borrowed", Span::call_site());
+ let borrowed = Cow::Borrowed(&ident);
+
+ let tokens = quote! { #owned #borrowed };
+ assert_eq!("owned borrowed", tokens.to_string());
+}
+
+#[test]
+fn test_closure() {
+ fn field_i(i: usize) -> Ident {
+ format_ident!("__field{}", i)
+ }
+
+ let fields = (0usize..3)
+ .map(field_i as fn(_) -> _)
+ .map(|var| quote! { #var });
+
+ let tokens = quote! { #(#fields)* };
+ assert_eq!("__field0 __field1 __field2", tokens.to_string());
+}
+
+#[test]
+fn test_append_tokens() {
+ let mut a = quote!(a);
+ let b = quote!(b);
+ a.append_all(b);
+ assert_eq!("a b", a.to_string());
+}
+
+#[test]
+fn test_format_ident() {
+ let id0 = format_ident!("Aa");
+ let id1 = format_ident!("Hello{x}", x = id0);
+ let id2 = format_ident!("Hello{x}", x = 5usize);
+ let id3 = format_ident!("Hello{}_{x}", id0, x = 10usize);
+ let id4 = format_ident!("Aa", span = Span::call_site());
+
+ assert_eq!(id0, "Aa");
+ assert_eq!(id1, "HelloAa");
+ assert_eq!(id2, "Hello5");
+ assert_eq!(id3, "HelloAa_10");
+ assert_eq!(id4, "Aa");
+}
+
+#[test]
+fn test_format_ident_strip_raw() {
+ let id = format_ident!("r#struct");
+ let my_id = format_ident!("MyId{}", id);
+ let raw_my_id = format_ident!("r#MyId{}", id);
+
+ assert_eq!(id, "r#struct");
+ assert_eq!(my_id, "MyIdstruct");
+ assert_eq!(raw_my_id, "r#MyIdstruct");
+}
+
+#[test]
+fn test_outer_line_comment() {
+ let tokens = quote! {
+ /// doc
+ };
+ let expected = "# [ doc = r\" doc\" ]";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_inner_line_comment() {
+ let tokens = quote! {
+ //! doc
+ };
+ let expected = "# ! [ doc = r\" doc\" ]";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_outer_block_comment() {
+ let tokens = quote! {
+ /** doc */
+ };
+ let expected = "# [ doc = r\" doc \" ]";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_inner_block_comment() {
+ let tokens = quote! {
+ /*! doc */
+ };
+ let expected = "# ! [ doc = r\" doc \" ]";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_outer_attr() {
+ let tokens = quote! {
+ #[inline]
+ };
+ let expected = "# [ inline ]";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_inner_attr() {
+ let tokens = quote! {
+ #![no_std]
+ };
+ let expected = "# ! [ no_std ]";
+ assert_eq!(expected, tokens.to_string());
+}
+
+// https://github.com/dtolnay/quote/issues/130
+#[test]
+fn test_star_after_repetition() {
+ let c = vec!['0', '1'];
+ let tokens = quote! {
+ #(
+ f(#c);
+ )*
+ *out = None;
+ };
+ let expected = "f ( '0' ) ; f ( '1' ) ; * out = None ;";
+ assert_eq!(expected, tokens.to_string());
+}
diff --git a/quote/tests/ui/does-not-have-iter-interpolated-dup.rs b/quote/tests/ui/does-not-have-iter-interpolated-dup.rs
new file mode 100644
index 0000000..0a39f41
--- /dev/null
+++ b/quote/tests/ui/does-not-have-iter-interpolated-dup.rs
@@ -0,0 +1,9 @@
+use quote::quote;
+
+fn main() {
+ let nonrep = "";
+
+ // Without some protection against repetitions with no iterator somewhere
+ // inside, this would loop infinitely.
+ quote!(#(#nonrep #nonrep)*);
+}
diff --git a/quote/tests/ui/does-not-have-iter-interpolated-dup.stderr b/quote/tests/ui/does-not-have-iter-interpolated-dup.stderr
new file mode 100644
index 0000000..6ee6fdf
--- /dev/null
+++ b/quote/tests/ui/does-not-have-iter-interpolated-dup.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+ --> $DIR/does-not-have-iter-interpolated-dup.rs:8:5
+ |
+8 | quote!(#(#nonrep #nonrep)*);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `quote::__rt::HasIterator`, found struct `quote::__rt::ThereIsNoIteratorInRepetition`
+ |
+ = note: expected type `quote::__rt::HasIterator`
+ found type `quote::__rt::ThereIsNoIteratorInRepetition`
+ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/quote/tests/ui/does-not-have-iter-interpolated.rs b/quote/tests/ui/does-not-have-iter-interpolated.rs
new file mode 100644
index 0000000..2c740cc
--- /dev/null
+++ b/quote/tests/ui/does-not-have-iter-interpolated.rs
@@ -0,0 +1,9 @@
+use quote::quote;
+
+fn main() {
+ let nonrep = "";
+
+ // Without some protection against repetitions with no iterator somewhere
+ // inside, this would loop infinitely.
+ quote!(#(#nonrep)*);
+}
diff --git a/quote/tests/ui/does-not-have-iter-interpolated.stderr b/quote/tests/ui/does-not-have-iter-interpolated.stderr
new file mode 100644
index 0000000..8d6c990
--- /dev/null
+++ b/quote/tests/ui/does-not-have-iter-interpolated.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+ --> $DIR/does-not-have-iter-interpolated.rs:8:5
+ |
+8 | quote!(#(#nonrep)*);
+ | ^^^^^^^^^^^^^^^^^^^^ expected struct `quote::__rt::HasIterator`, found struct `quote::__rt::ThereIsNoIteratorInRepetition`
+ |
+ = note: expected type `quote::__rt::HasIterator`
+ found type `quote::__rt::ThereIsNoIteratorInRepetition`
+ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/quote/tests/ui/does-not-have-iter-separated.rs b/quote/tests/ui/does-not-have-iter-separated.rs
new file mode 100644
index 0000000..c027243
--- /dev/null
+++ b/quote/tests/ui/does-not-have-iter-separated.rs
@@ -0,0 +1,5 @@
+use quote::quote;
+
+fn main() {
+ quote!(#(a b),*);
+}
diff --git a/quote/tests/ui/does-not-have-iter-separated.stderr b/quote/tests/ui/does-not-have-iter-separated.stderr
new file mode 100644
index 0000000..c1fd0ad
--- /dev/null
+++ b/quote/tests/ui/does-not-have-iter-separated.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+ --> $DIR/does-not-have-iter-separated.rs:4:5
+ |
+4 | quote!(#(a b),*);
+ | ^^^^^^^^^^^^^^^^^ expected struct `quote::__rt::HasIterator`, found struct `quote::__rt::ThereIsNoIteratorInRepetition`
+ |
+ = note: expected type `quote::__rt::HasIterator`
+ found type `quote::__rt::ThereIsNoIteratorInRepetition`
+ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/quote/tests/ui/does-not-have-iter.rs b/quote/tests/ui/does-not-have-iter.rs
new file mode 100644
index 0000000..8908353
--- /dev/null
+++ b/quote/tests/ui/does-not-have-iter.rs
@@ -0,0 +1,5 @@
+use quote::quote;
+
+fn main() {
+ quote!(#(a b)*);
+}
diff --git a/quote/tests/ui/does-not-have-iter.stderr b/quote/tests/ui/does-not-have-iter.stderr
new file mode 100644
index 0000000..3b87705
--- /dev/null
+++ b/quote/tests/ui/does-not-have-iter.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+ --> $DIR/does-not-have-iter.rs:4:5
+ |
+4 | quote!(#(a b)*);
+ | ^^^^^^^^^^^^^^^^ expected struct `quote::__rt::HasIterator`, found struct `quote::__rt::ThereIsNoIteratorInRepetition`
+ |
+ = note: expected type `quote::__rt::HasIterator`
+ found type `quote::__rt::ThereIsNoIteratorInRepetition`
+ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/quote/tests/ui/not-quotable.rs b/quote/tests/ui/not-quotable.rs
new file mode 100644
index 0000000..f991c18
--- /dev/null
+++ b/quote/tests/ui/not-quotable.rs
@@ -0,0 +1,7 @@
+use quote::quote;
+use std::net::Ipv4Addr;
+
+fn main() {
+ let ip = Ipv4Addr::LOCALHOST;
+ let _ = quote! { #ip };
+}
diff --git a/quote/tests/ui/not-quotable.stderr b/quote/tests/ui/not-quotable.stderr
new file mode 100644
index 0000000..f51f85f
--- /dev/null
+++ b/quote/tests/ui/not-quotable.stderr
@@ -0,0 +1,10 @@
+error[E0277]: the trait bound `std::net::Ipv4Addr: quote::to_tokens::ToTokens` is not satisfied
+ --> $DIR/not-quotable.rs:6:13
+ |
+6 | let _ = quote! { #ip };
+ | ^^^^^^^^^^^^^^ the trait `quote::to_tokens::ToTokens` is not implemented for `std::net::Ipv4Addr`
+ |
+ = note: required by `quote::to_tokens::ToTokens::to_tokens`
+ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/quote/tests/ui/not-repeatable.rs b/quote/tests/ui/not-repeatable.rs
new file mode 100644
index 0000000..ff18060
--- /dev/null
+++ b/quote/tests/ui/not-repeatable.rs
@@ -0,0 +1,7 @@
+use quote::quote;
+use std::net::Ipv4Addr;
+
+fn main() {
+ let ip = Ipv4Addr::LOCALHOST;
+ let _ = quote! { #(#ip)* };
+}
diff --git a/quote/tests/ui/not-repeatable.stderr b/quote/tests/ui/not-repeatable.stderr
new file mode 100644
index 0000000..ddcac05
--- /dev/null
+++ b/quote/tests/ui/not-repeatable.stderr
@@ -0,0 +1,14 @@
+error[E0599]: no method named `quote_into_iter` found for type `std::net::Ipv4Addr` in the current scope
+ --> $DIR/not-repeatable.rs:6:13
+ |
+6 | let _ = quote! { #(#ip)* };
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: the method `quote_into_iter` exists but the following trait bounds were not satisfied:
+ `&mut std::net::Ipv4Addr : quote::__rt::ext::RepIteratorExt`
+ `&std::net::Ipv4Addr : quote::__rt::ext::RepIteratorExt`
+ `std::net::Ipv4Addr : quote::__rt::ext::RepIteratorExt`
+ `std::net::Ipv4Addr : quote::__rt::ext::RepToTokensExt`
+ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/quote/tests/ui/wrong-type-span.rs b/quote/tests/ui/wrong-type-span.rs
new file mode 100644
index 0000000..1ce391c
--- /dev/null
+++ b/quote/tests/ui/wrong-type-span.rs
@@ -0,0 +1,7 @@
+use quote::quote_spanned;
+
+fn main() {
+ let span = "";
+ let x = 0;
+ quote_spanned!(span=> #x);
+}
diff --git a/quote/tests/ui/wrong-type-span.stderr b/quote/tests/ui/wrong-type-span.stderr
new file mode 100644
index 0000000..a6ae8ef
--- /dev/null
+++ b/quote/tests/ui/wrong-type-span.stderr
@@ -0,0 +1,10 @@
+error[E0308]: mismatched types
+ --> $DIR/wrong-type-span.rs:6:20
+ |
+6 | quote_spanned!(span=> #x);
+ | ^^^^ expected struct `proc_macro2::Span`, found &str
+ |
+ = note: expected type `proc_macro2::Span`
+ found type `&str`
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/rustversion/.gitignore b/rustversion/.gitignore
new file mode 100644
index 0000000..6936990
--- /dev/null
+++ b/rustversion/.gitignore
@@ -0,0 +1,3 @@
+/target
+**/*.rs.bk
+Cargo.lock
diff --git a/rustversion/.travis.yml b/rustversion/.travis.yml
new file mode 100644
index 0000000..1a615ba
--- /dev/null
+++ b/rustversion/.travis.yml
@@ -0,0 +1,17 @@
+language: rust
+
+rust:
+ - nightly
+ - beta
+ - stable
+ - 1.31.0
+
+script:
+ - cargo test
+
+matrix:
+ include:
+ - rust: nightly
+ name: Minimal versions
+ before_script:
+ - cargo update -Z minimal-versions
diff --git a/rustversion/Cargo.toml b/rustversion/Cargo.toml
new file mode 100644
index 0000000..789c5f4
--- /dev/null
+++ b/rustversion/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "rustversion"
+version = "1.0.1"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+license = "MIT OR Apache-2.0"
+description = "Conditional compilation according to rustc compiler version"
+repository = "https://github.com/dtolnay/rustversion"
+documentation = "https://docs.rs/rustversion"
+readme = "README.md"
+
+[lib]
+proc-macro = true
+
+[badges]
+travis-ci = { repository = "dtolnay/rustversion" }
+
+[dependencies]
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "1.0.1", features = ["full"] }
diff --git a/rustversion/LICENSE-APACHE b/rustversion/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/rustversion/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rustversion/LICENSE-MIT b/rustversion/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/rustversion/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/rustversion/README.md b/rustversion/README.md
new file mode 100644
index 0000000..f7fdab1
--- /dev/null
+++ b/rustversion/README.md
@@ -0,0 +1,138 @@
+Compiler version cfg
+====================
+
+[![Build Status](https://api.travis-ci.com/dtolnay/rustversion.svg?branch=master)](https://travis-ci.com/dtolnay/rustversion)
+[![Latest Version](https://img.shields.io/crates/v/rustversion.svg)](https://crates.io/crates/rustversion)
+[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/rustversion)
+
+This crate provides macros for conditional compilation according to rustc
+compiler version, analogous to [`#[cfg(...)]`][cfg] and
+[`#[cfg_attr(...)]`][cfg_attr].
+
+[cfg]: https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute
+[cfg_attr]: https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute
+
+```toml
+[dependencies]
+rustversion = "1.0"
+```
+
+<br>
+
+## Selectors
+
+- <b>`#[rustversion::stable]`</b>
+ —<br>
+ True on any stable compiler.
+
+- <b>`#[rustversion::stable(1.34)]`</b>
+ —<br>
+ True on exactly the specified stable compiler.
+
+- <b>`#[rustversion::beta]`</b>
+ —<br>
+ True on any beta compiler.
+
+- <b>`#[rustversion::nightly]`</b>
+ —<br>
+ True on any nightly compiler or dev build.
+
+- <b>`#[rustversion::nightly(2019-01-01)]`</b>
+ —<br>
+ True on exactly one nightly.
+
+- <b>`#[rustversion::since(1.34)]`</b>
+ —<br>
+ True on that stable release and any later compiler, including beta and
+ nightly.
+
+- <b>`#[rustversion::since(2019-01-01)]`</b>
+ —<br>
+ True on that nightly and all newer ones.
+
+- <b>`#[rustversion::before(`</b><i>version or date</i><b>`)]`</b>
+ —<br>
+ Negative of *#[rustversion::since(...)]*.
+
+- <b>`#[rustversion::not(`</b><i>selector</i><b>`)]`</b>
+ —<br>
+ Negative of any selector; for example *#[rustversion::not(nightly)]*.
+
+- <b>`#[rustversion::any(`</b><i>selectors...</i><b>`)]`</b>
+ —<br>
+ True if any of the comma-separated selectors is true; for example
+ *#[rustversion::any(stable, beta)]*.
+
+- <b>`#[rustversion::all(`</b><i>selectors...</i><b>`)]`</b>
+ —<br>
+ True if all of the comma-separated selectors are true; for example
+ *#[rustversion::all(since(1.31), before(1.34))]*.
+
+- <b>`#[rustversion::attr(`</b><i>selector</i><b>`, `</b><i>attribute</i><b>`)]`</b>
+ —<br>
+ For conditional inclusion of attributes; analogous to `cfg_attr`.
+
+<br>
+
+## Use cases
+
+Providing additional trait impls as types are stabilized in the standard library
+without breaking compatibility with older compilers; in this case Pin\<P\>
+stabilized in [Rust 1.33][pin]:
+
+[pin]: https://blog.rust-lang.org/2019/02/28/Rust-1.33.0.html#pinning
+
+```rust
+#[rustversion::since(1.33)]
+use std::pin::Pin;
+
+#[rustversion::since(1.33)]
+impl<P: MyTrait> MyTrait for Pin<P> {
+ /* ... */
+}
+```
+
+Similar but for language features; the ability to control alignment greater than
+1 of packed structs was stabilized in [Rust 1.33][packed].
+
+[packed]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1330-2019-02-28
+
+```rust
+#[rustversion::attr(before(1.33), repr(packed))]
+#[rustversion::attr(since(1.33), repr(packed(2)))]
+struct Six(i16, i32);
+
+fn main() {
+ println!("{}", std::mem::align_of::<Six>());
+}
+```
+
+Augmenting code with `const` as const impls are stabilized in the standard
+library. This use of `const` as an attribute is recognized as a special case by
+the rustversion::attr macro.
+
+```rust
+use std::time::Duration;
+
+#[rustversion::attr(since(1.32), const)]
+fn duration_as_days(dur: Duration) -> u64 {
+ dur.as_secs() / 60 / 60 / 24
+}
+```
+
+<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/rustversion/src/attr.rs b/rustversion/src/attr.rs
new file mode 100644
index 0000000..591b2c0
--- /dev/null
+++ b/rustversion/src/attr.rs
@@ -0,0 +1,35 @@
+use crate::expr::Expr;
+use proc_macro2::TokenStream;
+use syn::parse::{Parse, ParseStream, Result};
+use syn::Token;
+
+pub struct Args {
+ pub condition: Expr,
+ pub then: Then,
+}
+
+pub enum Then {
+ Const(Token![const]),
+ Attribute(TokenStream),
+}
+
+impl Parse for Args {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let condition: Expr = input.parse()?;
+
+ input.parse::<Token![,]>()?;
+ if input.is_empty() {
+ return Err(input.error("expected one or more attrs"));
+ }
+
+ let const_token: Option<Token![const]> = input.parse()?;
+ let then = if let Some(const_token) = const_token {
+ input.parse::<Option<Token![,]>>()?;
+ Then::Const(const_token)
+ } else {
+ input.parse().map(Then::Attribute)?
+ };
+
+ Ok(Args { condition, then })
+ }
+}
diff --git a/rustversion/src/bound.rs b/rustversion/src/bound.rs
new file mode 100644
index 0000000..2546637
--- /dev/null
+++ b/rustversion/src/bound.rs
@@ -0,0 +1,84 @@
+use crate::date::Date;
+use crate::version::{Channel::*, Version};
+use quote::quote;
+use std::cmp::Ordering;
+use syn::parse::{Error, Parse, ParseStream, Result};
+use syn::{LitFloat, LitInt, Token};
+
+pub enum Bound {
+ Nightly(Date),
+ Stable(Release),
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Release {
+ pub minor: u16,
+ pub patch: Option<u16>,
+}
+
+impl Parse for Bound {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek2(Token![-]) {
+ input.parse().map(Bound::Nightly)
+ } else {
+ input.parse().map(Bound::Stable)
+ }
+ }
+}
+
+impl Parse for Release {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let span = input.cursor().token_stream();
+ let error = || Error::new_spanned(&span, "expected rustc release number, like 1.31");
+
+ let major_minor: LitFloat = input.parse().map_err(|_| error())?;
+ let string = quote!(#major_minor).to_string();
+
+ if !string.starts_with("1.") {
+ return Err(error());
+ }
+
+ let minor: u16 = string[2..].parse().map_err(|_| error())?;
+
+ let patch = if input.parse::<Option<Token![.]>>()?.is_some() {
+ let int: LitInt = input.parse().map_err(|_| error())?;
+ Some(int.base10_parse().map_err(|_| error())?)
+ } else {
+ None
+ };
+
+ Ok(Release { minor, patch })
+ }
+}
+
+impl PartialEq<Bound> for Version {
+ fn eq(&self, rhs: &Bound) -> bool {
+ match rhs {
+ Bound::Nightly(date) => match self.channel {
+ Stable | Beta | Dev => false,
+ Nightly(nightly) => nightly == *date,
+ },
+ Bound::Stable(release) => {
+ self.minor == release.minor
+ && release.patch.map_or(true, |patch| self.patch == patch)
+ }
+ }
+ }
+}
+
+impl PartialOrd<Bound> for Version {
+ fn partial_cmp(&self, rhs: &Bound) -> Option<Ordering> {
+ match rhs {
+ Bound::Nightly(date) => match self.channel {
+ Stable | Beta => Some(Ordering::Less),
+ Nightly(nightly) => Some(nightly.cmp(date)),
+ Dev => Some(Ordering::Greater),
+ },
+ Bound::Stable(release) => {
+ let version = (self.minor, self.patch);
+ let bound = (release.minor, release.patch.unwrap_or(0));
+ Some(version.cmp(&bound))
+ }
+ }
+ }
+}
diff --git a/rustversion/src/date.rs b/rustversion/src/date.rs
new file mode 100644
index 0000000..631b762
--- /dev/null
+++ b/rustversion/src/date.rs
@@ -0,0 +1,77 @@
+use crate::time;
+use std::fmt::{self, Display};
+use std::num::ParseIntError;
+use std::str::FromStr;
+use syn::parse::{Error, Parse, ParseStream};
+use syn::{LitInt, Token};
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Date {
+ pub year: u16,
+ pub month: u8,
+ pub day: u8,
+}
+
+impl Display for Date {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ formatter,
+ "{:04}-{:02}-{:02}",
+ self.year, self.month, self.day,
+ )
+ }
+}
+
+pub struct ParseDateError;
+
+impl From<ParseIntError> for ParseDateError {
+ fn from(_err: ParseIntError) -> Self {
+ ParseDateError
+ }
+}
+
+impl FromStr for Date {
+ type Err = ParseDateError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let mut date = s.split('-');
+ let year = date.next().ok_or(ParseDateError)?.parse()?;
+ let month = date.next().ok_or(ParseDateError)?.parse()?;
+ let day = date.next().ok_or(ParseDateError)?.parse()?;
+ match date.next() {
+ None => Ok(Date { year, month, day }),
+ Some(_) => Err(ParseDateError),
+ }
+ }
+}
+
+impl Parse for Date {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let span = input.cursor().token_stream();
+ let error = || {
+ Error::new_spanned(
+ &span,
+ format!("expected nightly date, like {}", time::today()),
+ )
+ };
+
+ let year: LitInt = input.parse().map_err(|_| error())?;
+ input.parse::<Token![-]>()?;
+ let month: LitInt = input.parse().map_err(|_| error())?;
+ input.parse::<Token![-]>()?;
+ let day: LitInt = input.parse().map_err(|_| error())?;
+
+ let year = year.base10_parse::<u64>().map_err(|_| error())?;
+ let month = month.base10_parse::<u64>().map_err(|_| error())?;
+ let day = day.base10_parse::<u64>().map_err(|_| error())?;
+ if year >= 3000 || month > 12 || day > 31 {
+ return Err(error());
+ }
+
+ Ok(Date {
+ year: year as u16,
+ month: month as u8,
+ day: day as u8,
+ })
+ }
+}
diff --git a/rustversion/src/expr.rs b/rustversion/src/expr.rs
new file mode 100644
index 0000000..2ea91af
--- /dev/null
+++ b/rustversion/src/expr.rs
@@ -0,0 +1,177 @@
+use crate::bound::{Bound, Release};
+use crate::date::Date;
+use crate::version::{Channel, Version};
+use syn::parse::{Parse, ParseStream, Result};
+use syn::punctuated::Punctuated;
+use syn::{parenthesized, token, Token};
+
+pub enum Expr {
+ Stable,
+ Beta,
+ Nightly,
+ Date(Date),
+ Since(Bound),
+ Before(Bound),
+ Release(Release),
+ Not(Box<Expr>),
+ Any(Vec<Expr>),
+ All(Vec<Expr>),
+}
+
+impl Expr {
+ pub fn eval(&self, rustc: Version) -> bool {
+ use self::Expr::*;
+
+ match self {
+ Stable => rustc.channel == Channel::Stable,
+ Beta => rustc.channel == Channel::Beta,
+ Nightly => match rustc.channel {
+ Channel::Nightly(_) | Channel::Dev => true,
+ Channel::Stable | Channel::Beta => false,
+ },
+ Date(date) => match rustc.channel {
+ Channel::Nightly(rustc) => rustc == *date,
+ Channel::Stable | Channel::Beta | Channel::Dev => false,
+ },
+ Since(bound) => rustc >= *bound,
+ Before(bound) => rustc < *bound,
+ Release(release) => {
+ rustc.channel == Channel::Stable
+ && rustc.minor == release.minor
+ && release.patch.map_or(true, |patch| rustc.patch == patch)
+ }
+ Not(expr) => !expr.eval(rustc),
+ Any(exprs) => exprs.iter().any(|e| e.eval(rustc)),
+ All(exprs) => exprs.iter().all(|e| e.eval(rustc)),
+ }
+ }
+}
+
+type Exprs = Punctuated<Expr, Token![,]>;
+
+mod keyword {
+ syn::custom_keyword!(stable);
+ syn::custom_keyword!(beta);
+ syn::custom_keyword!(nightly);
+ syn::custom_keyword!(since);
+ syn::custom_keyword!(before);
+ syn::custom_keyword!(not);
+ syn::custom_keyword!(any);
+ syn::custom_keyword!(all);
+}
+
+impl Parse for Expr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(keyword::stable) {
+ Self::parse_stable(input)
+ } else if lookahead.peek(keyword::beta) {
+ Self::parse_beta(input)
+ } else if lookahead.peek(keyword::nightly) {
+ Self::parse_nightly(input)
+ } else if lookahead.peek(keyword::since) {
+ Self::parse_since(input)
+ } else if lookahead.peek(keyword::before) {
+ Self::parse_before(input)
+ } else if lookahead.peek(keyword::not) {
+ Self::parse_not(input)
+ } else if lookahead.peek(keyword::any) {
+ Self::parse_any(input)
+ } else if lookahead.peek(keyword::all) {
+ Self::parse_all(input)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
+
+impl Expr {
+ fn parse_nightly(input: ParseStream) -> Result<Self> {
+ input.parse::<keyword::nightly>()?;
+
+ if !input.peek(token::Paren) {
+ return Ok(Expr::Nightly);
+ }
+
+ let paren;
+ parenthesized!(paren in input);
+ let date: Date = paren.parse()?;
+ paren.parse::<Option<Token![,]>>()?;
+
+ Ok(Expr::Date(date))
+ }
+
+ fn parse_beta(input: ParseStream) -> Result<Self> {
+ input.parse::<keyword::beta>()?;
+
+ Ok(Expr::Beta)
+ }
+
+ fn parse_stable(input: ParseStream) -> Result<Self> {
+ input.parse::<keyword::stable>()?;
+
+ if !input.peek(token::Paren) {
+ return Ok(Expr::Stable);
+ }
+
+ let paren;
+ parenthesized!(paren in input);
+ let release: Release = paren.parse()?;
+ paren.parse::<Option<Token![,]>>()?;
+
+ Ok(Expr::Release(release))
+ }
+
+ fn parse_since(input: ParseStream) -> Result<Self> {
+ input.parse::<keyword::since>()?;
+
+ let paren;
+ parenthesized!(paren in input);
+ let bound: Bound = paren.parse()?;
+ paren.parse::<Option<Token![,]>>()?;
+
+ Ok(Expr::Since(bound))
+ }
+
+ fn parse_before(input: ParseStream) -> Result<Self> {
+ input.parse::<keyword::before>()?;
+
+ let paren;
+ parenthesized!(paren in input);
+ let bound: Bound = paren.parse()?;
+ paren.parse::<Option<Token![,]>>()?;
+
+ Ok(Expr::Before(bound))
+ }
+
+ fn parse_not(input: ParseStream) -> Result<Self> {
+ input.parse::<keyword::not>()?;
+
+ let paren;
+ parenthesized!(paren in input);
+ let expr: Expr = paren.parse()?;
+ paren.parse::<Option<Token![,]>>()?;
+
+ Ok(Expr::Not(Box::new(expr)))
+ }
+
+ fn parse_any(input: ParseStream) -> Result<Self> {
+ input.parse::<keyword::any>()?;
+
+ let paren;
+ parenthesized!(paren in input);
+ let exprs: Exprs = paren.parse_terminated(Expr::parse)?;
+
+ Ok(Expr::Any(exprs.into_iter().collect()))
+ }
+
+ fn parse_all(input: ParseStream) -> Result<Self> {
+ input.parse::<keyword::all>()?;
+
+ let paren;
+ parenthesized!(paren in input);
+ let exprs: Exprs = paren.parse_terminated(Expr::parse)?;
+
+ Ok(Expr::All(exprs.into_iter().collect()))
+ }
+}
diff --git a/rustversion/src/lib.rs b/rustversion/src/lib.rs
new file mode 100644
index 0000000..cf8ed21
--- /dev/null
+++ b/rustversion/src/lib.rs
@@ -0,0 +1,254 @@
+//! This crate provides macros for conditional compilation according to rustc
+//! compiler version, analogous to [`#[cfg(...)]`][cfg] and
+//! [`#[cfg_attr(...)]`][cfg_attr].
+//!
+//! [cfg]: https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute
+//! [cfg_attr]: https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute
+//!
+//! <br>
+//!
+//! # Selectors
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::stable]</code></b>
+//! —<br>
+//! True on any stable compiler.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::stable(1.34)]</code></b>
+//! —<br>
+//! True on exactly the specified stable compiler.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::beta]</code></b>
+//! —<br>
+//! True on any beta compiler.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::nightly]</code></b>
+//! —<br>
+//! True on any nightly compiler or dev build.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::nightly(2019-01-01)]</code></b>
+//! —<br>
+//! True on exactly one nightly.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::since(1.34)]</code></b>
+//! —<br>
+//! True on that stable release and any later compiler, including beta and
+//! nightly.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::since(2019-01-01)]</code></b>
+//! —<br>
+//! True on that nightly and all newer ones.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::before(</code></b><i>version or date</i><b><code>)]</code></b>
+//! —<br>
+//! Negative of <i>#[rustversion::since(...)]</i>.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::not(</code></b><i>selector</i><b><code>)]</code></b>
+//! —<br>
+//! Negative of any selector; for example <i>#[rustversion::not(nightly)]</i>.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::any(</code></b><i>selectors...</i><b><code>)]</code></b>
+//! —<br>
+//! True if any of the comma-separated selectors is true; for example
+//! <i>#[rustversion::any(stable, beta)]</i>.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::all(</code></b><i>selectors...</i><b><code>)]</code></b>
+//! —<br>
+//! True if all of the comma-separated selectors are true; for example
+//! <i>#[rustversion::all(since(1.31), before(1.34))]</i>.
+//! </p>
+//!
+//! - <p style="margin-left:50px;text-indent:-50px">
+//! <b><code>#[rustversion::attr(</code></b><i>selector</i><b><code>, </code></b><i>attribute</i><b><code>)]</code></b>
+//! —<br>
+//! For conditional inclusion of attributes; analogous to
+//! <code>cfg_attr</code>.
+//! </p>
+//!
+//! <br>
+//!
+//! # Use cases
+//!
+//! Providing additional trait impls as types are stabilized in the standard library
+//! without breaking compatibility with older compilers; in this case Pin\<P\>
+//! stabilized in [Rust 1.33][pin]:
+//!
+//! [pin]: https://blog.rust-lang.org/2019/02/28/Rust-1.33.0.html#pinning
+//!
+//! ```
+//! # trait MyTrait {}
+//! #
+//! #[rustversion::since(1.33)]
+//! use std::pin::Pin;
+//!
+//! #[rustversion::since(1.33)]
+//! impl<P: MyTrait> MyTrait for Pin<P> {
+//! /* ... */
+//! }
+//! ```
+//!
+//! Similar but for language features; the ability to control alignment greater than
+//! 1 of packed structs was stabilized in [Rust 1.33][packed].
+//!
+//! [packed]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1330-2019-02-28
+//!
+//! ```
+//! #[rustversion::attr(before(1.33), repr(packed))]
+//! #[rustversion::attr(since(1.33), repr(packed(2)))]
+//! struct Six(i16, i32);
+//!
+//! fn main() {
+//! println!("{}", std::mem::align_of::<Six>());
+//! }
+//! ```
+//!
+//! Augmenting code with `const` as const impls are stabilized in the standard
+//! library. This use of `const` as an attribute is recognized as a special case
+//! by the rustversion::attr macro.
+//!
+//! ```
+//! use std::time::Duration;
+//!
+//! #[rustversion::attr(since(1.32), const)]
+//! fn duration_as_days(dur: Duration) -> u64 {
+//! dur.as_secs() / 60 / 60 / 24
+//! }
+//! ```
+//!
+//! <br>
+
+extern crate proc_macro;
+
+mod attr;
+mod bound;
+mod date;
+mod expr;
+mod rustc;
+mod time;
+mod version;
+
+use crate::attr::Then;
+use crate::expr::Expr;
+use proc_macro::TokenStream;
+use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
+use quote::quote;
+use syn::{parse_macro_input, ItemFn, Result};
+
+#[proc_macro_attribute]
+pub fn stable(args: TokenStream, input: TokenStream) -> TokenStream {
+ cfg("stable", args, input)
+}
+
+#[proc_macro_attribute]
+pub fn beta(args: TokenStream, input: TokenStream) -> TokenStream {
+ cfg("beta", args, input)
+}
+
+#[proc_macro_attribute]
+pub fn nightly(args: TokenStream, input: TokenStream) -> TokenStream {
+ cfg("nightly", args, input)
+}
+
+#[proc_macro_attribute]
+pub fn since(args: TokenStream, input: TokenStream) -> TokenStream {
+ cfg("since", args, input)
+}
+
+#[proc_macro_attribute]
+pub fn before(args: TokenStream, input: TokenStream) -> TokenStream {
+ cfg("before", args, input)
+}
+
+#[proc_macro_attribute]
+pub fn not(args: TokenStream, input: TokenStream) -> TokenStream {
+ cfg("not", args, input)
+}
+
+#[proc_macro_attribute]
+pub fn any(args: TokenStream, input: TokenStream) -> TokenStream {
+ cfg("any", args, input)
+}
+
+#[proc_macro_attribute]
+pub fn all(args: TokenStream, input: TokenStream) -> TokenStream {
+ cfg("all", args, input)
+}
+
+fn cfg(top: &str, args: TokenStream, input: TokenStream) -> TokenStream {
+ match try_cfg(top, args, input) {
+ Ok(tokens) => tokens,
+ Err(err) => TokenStream::from(err.to_compile_error()),
+ }
+}
+
+fn try_cfg(top: &str, args: TokenStream, input: TokenStream) -> Result<TokenStream> {
+ let args = TokenStream2::from(args);
+ let top = Ident::new(top, Span::call_site());
+
+ let mut full_args = quote!(#top);
+ if !args.is_empty() {
+ full_args.extend(quote!((#args)));
+ }
+
+ let expr: Expr = syn::parse2(full_args)?;
+ let version = rustc::version()?;
+
+ if expr.eval(version) {
+ Ok(input)
+ } else {
+ Ok(TokenStream::new())
+ }
+}
+
+#[proc_macro_attribute]
+pub fn attr(args: TokenStream, input: TokenStream) -> TokenStream {
+ let args = parse_macro_input!(args as attr::Args);
+
+ match try_attr(args, input) {
+ Ok(tokens) => tokens,
+ Err(err) => TokenStream::from(err.to_compile_error()),
+ }
+}
+
+fn try_attr(args: attr::Args, input: TokenStream) -> Result<TokenStream> {
+ let version = rustc::version()?;
+
+ if !args.condition.eval(version) {
+ return Ok(input);
+ }
+
+ match args.then {
+ Then::Const(const_token) => {
+ let mut input: ItemFn = syn::parse(input)?;
+ input.sig.constness = Some(const_token);
+ Ok(TokenStream::from(quote!(#input)))
+ }
+ Then::Attribute(then) => {
+ let input = TokenStream2::from(input);
+ Ok(TokenStream::from(quote! {
+ #[cfg_attr(all(), #then)]
+ #input
+ }))
+ }
+ }
+}
diff --git a/rustversion/src/rustc.rs b/rustversion/src/rustc.rs
new file mode 100644
index 0000000..4e7699d
--- /dev/null
+++ b/rustversion/src/rustc.rs
@@ -0,0 +1,195 @@
+use std::env;
+use std::ffi::OsString;
+use std::fmt::{self, Display};
+use std::io;
+use std::process::Command;
+use std::str::FromStr;
+use std::string::FromUtf8Error;
+
+use crate::date::Date;
+use crate::version::{Channel::*, Version};
+use proc_macro2::Span;
+
+#[derive(Debug)]
+pub enum Error {
+ Exec(io::Error),
+ Utf8(FromUtf8Error),
+ Parse(String),
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+impl Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::Error::*;
+
+ match self {
+ Exec(e) => write!(f, "failed to run `rustc --version`: {}", e),
+ Utf8(e) => write!(f, "failed to parse output of `rustc --version`: {}", e),
+ Parse(string) => write!(
+ f,
+ "unexpected output from `rustc --version`, please file an issue: {:?}",
+ string,
+ ),
+ }
+ }
+}
+
+impl From<FromUtf8Error> for Error {
+ fn from(err: FromUtf8Error) -> Self {
+ Error::Utf8(err)
+ }
+}
+
+impl From<Error> for syn::Error {
+ fn from(err: Error) -> Self {
+ syn::Error::new(Span::call_site(), err)
+ }
+}
+
+pub fn version() -> Result<Version> {
+ let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
+ let output = Command::new(rustc)
+ .arg("--version")
+ .output()
+ .map_err(Error::Exec)?;
+ let string = String::from_utf8(output.stdout)?;
+
+ match parse(&string) {
+ Some(version) => Ok(version),
+ None => Err(Error::Parse(string)),
+ }
+}
+
+fn parse(string: &str) -> Option<Version> {
+ let last_line = string.lines().last().unwrap_or(&string);
+ let mut words = last_line.trim().split(' ');
+
+ if words.next()? != "rustc" {
+ return None;
+ }
+
+ let mut version_channel = words.next()?.split('-');
+ let version = version_channel.next()?;
+ let channel = version_channel.next();
+
+ let mut digits = version.split('.');
+ let major = digits.next()?;
+ if major != "1" {
+ return None;
+ }
+ let minor = digits.next()?.parse().ok()?;
+ let patch = digits.next().unwrap_or("0").parse().ok()?;
+
+ let channel = match channel {
+ None => Stable,
+ Some(channel) if channel == "dev" => Dev,
+ Some(channel) if channel.starts_with("beta") => Beta,
+ Some(channel) if channel == "nightly" => {
+ match words.next() {
+ Some(hash) => {
+ if !hash.starts_with('(') {
+ return None;
+ }
+ let date = words.next()?;
+ if !date.ends_with(')') {
+ return None;
+ }
+ let date = Date::from_str(&date[..date.len() - 1]).ok()?;
+ Nightly(date)
+ }
+ None => Dev,
+ }
+ }
+ Some(_) => return None,
+ };
+
+ Some(Version {
+ minor,
+ patch,
+ channel,
+ })
+}
+
+#[test]
+fn test_parse() {
+ let cases = &[
+ (
+ "rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)",
+ Version {
+ minor: 0,
+ patch: 0,
+ channel: Stable,
+ },
+ ),
+ (
+ "rustc 1.18.0",
+ Version {
+ minor: 18,
+ patch: 0,
+ channel: Stable,
+ },
+ ),
+ (
+ "rustc 1.24.1 (d3ae9a9e0 2018-02-27)",
+ Version {
+ minor: 24,
+ patch: 1,
+ channel: Stable,
+ },
+ ),
+ (
+ "rustc 1.35.0-beta.3 (c13114dc8 2019-04-27)",
+ Version {
+ minor: 35,
+ patch: 0,
+ channel: Beta,
+ },
+ ),
+ (
+ "rustc 1.36.0-nightly (938d4ffe1 2019-04-27)",
+ Version {
+ minor: 36,
+ patch: 0,
+ channel: Nightly(Date {
+ year: 2019,
+ month: 4,
+ day: 27,
+ }),
+ },
+ ),
+ (
+ "rustc 1.36.0-dev",
+ Version {
+ minor: 36,
+ patch: 0,
+ channel: Dev,
+ },
+ ),
+ (
+ "rustc 1.36.0-nightly",
+ Version {
+ minor: 36,
+ patch: 0,
+ channel: Dev,
+ },
+ ),
+ (
+ "warning: invalid logging spec 'warning', ignoring it
+ rustc 1.30.0-nightly (3bc2ca7e4 2018-09-20)",
+ Version {
+ minor: 30,
+ patch: 0,
+ channel: Nightly(Date {
+ year: 2018,
+ month: 9,
+ day: 20,
+ }),
+ },
+ ),
+ ];
+
+ for (string, expected) in cases {
+ assert_eq!(parse(string).unwrap(), *expected);
+ }
+}
diff --git a/rustversion/src/time.rs b/rustversion/src/time.rs
new file mode 100644
index 0000000..1e6dd90
--- /dev/null
+++ b/rustversion/src/time.rs
@@ -0,0 +1,44 @@
+use crate::date::Date;
+use std::time::{SystemTime, UNIX_EPOCH};
+
+// Timestamp of 2016-03-01 00:00:00 in UTC.
+const BASE: u64 = 1456790400;
+const BASE_YEAR: u16 = 2016;
+const BASE_MONTH: u8 = 3;
+
+// Days between leap days.
+const CYCLE: u64 = 365 * 4 + 1;
+
+const DAYS_BY_MONTH: [u8; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+
+pub fn today() -> Date {
+ let default = Date {
+ year: 2019,
+ month: 1,
+ day: 1,
+ };
+ try_today().unwrap_or(default)
+}
+
+fn try_today() -> Option<Date> {
+ let now = SystemTime::now();
+ let since_epoch = now.duration_since(UNIX_EPOCH).ok()?;
+ let secs = since_epoch.as_secs();
+
+ let approx_days = secs.checked_sub(BASE)? / 60 / 60 / 24;
+ let cycle = approx_days / CYCLE;
+ let mut rem = approx_days % CYCLE;
+
+ let mut year = BASE_YEAR + cycle as u16 * 4;
+ let mut month = BASE_MONTH;
+ loop {
+ let days_in_month = DAYS_BY_MONTH[month as usize - 1];
+ if rem < days_in_month as u64 {
+ let day = rem as u8 + 1;
+ return Some(Date { year, month, day });
+ }
+ rem -= days_in_month as u64;
+ year += (month == 12) as u16;
+ month = month % 12 + 1;
+ }
+}
diff --git a/rustversion/src/version.rs b/rustversion/src/version.rs
new file mode 100644
index 0000000..ab3992f
--- /dev/null
+++ b/rustversion/src/version.rs
@@ -0,0 +1,16 @@
+use crate::date::Date;
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub struct Version {
+ pub minor: u16,
+ pub patch: u16,
+ pub channel: Channel,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum Channel {
+ Stable,
+ Beta,
+ Nightly(Date),
+ Dev,
+}
diff --git a/structopt/.gitignore b/structopt/.gitignore
new file mode 100644
index 0000000..ea63af4
--- /dev/null
+++ b/structopt/.gitignore
@@ -0,0 +1,6 @@
+target
+Cargo.lock
+*~
+
+.idea/
+.vscode/
diff --git a/structopt/.travis.yml b/structopt/.travis.yml
new file mode 100644
index 0000000..dff3050
--- /dev/null
+++ b/structopt/.travis.yml
@@ -0,0 +1,24 @@
+language: rust
+matrix:
+ include:
+ - rust: stable
+ name: check if `cargo fmt --all` is applied
+ before_script: rustup component add rustfmt-preview
+ script: cargo fmt --all -- --check
+
+ - language: node_js
+ node_js: node
+ name: check links
+ install: npm install -g markdown-link-check
+ script:
+ - markdown-link-check -c link-check-headers.json README.md
+ - markdown-link-check -c link-check-headers.json CHANGELOG.md
+ - markdown-link-check -c link-check-headers.json examples/README.md
+
+ - rust: 1.36.0
+ - rust: stable
+ - rust: beta
+ - rust: nightly
+
+script:
+ - cargo test $FEATURES
diff --git a/structopt/CHANGELOG.md b/structopt/CHANGELOG.md
new file mode 100644
index 0000000..ed2a17f
--- /dev/null
+++ b/structopt/CHANGELOG.md
@@ -0,0 +1,444 @@
+# v0.3.7 (2019-12-28)
+
+Nothing's new. Just re-release of `v0.3.6` due to
+[the mess with versioning](https://github.com/TeXitoi/structopt/issues/315#issuecomment-568502792).
+
+You may notice that `structopt-derive` was bumped to `v0.4.0`, that's OK, it's not a breaking change.
+`structopt` will pull the right version in on its on.
+
+# v0.3.6 (2019-12-22) - YANKED
+
+This is unusually big patch release. It contains a number of bugfixes and
+new features, some of them may theoretically be considered breaking. We did our best
+to avoid any problems on user's side but, if it wasn't good enough, please
+[file an issue ASAP](https://github.com/TeXitoi/structopt/issues).
+
+## Bugfixes
+
+* `structopt` used to treat `::path::to::type::Vec<T>` as `Vec<T>`
+ special type. [This was considered erroneous](https://github.com/TeXitoi/structopt/pull/287).
+ (same for `Option<T>` and `bool`). Now only exact `Vec<T>` match is a special type.
+
+* `#[structopt(version = expr)]` where `expr` is not a string literal used to get
+ overridden by auto generated `.version()` call,
+ [incorrectly](https://github.com/TeXitoi/structopt/issues/283). Now it doesn't.
+
+* Fixed bug with top-level `App::*` calls on multiple `struct`s, see
+ [#289](https://github.com/TeXitoi/structopt/issues/265).
+
+* Positional `bool` args with no explicit `#[structopt(parse(...))]` annotation are
+ now prohibited. This couldn't work well anyway, see
+ [this example](https://github.com/TeXitoi/structopt/blob/master/examples/true_or_false.rs)
+ for details.
+
+* Now we've instituted strict priority between doc comments, about, help, and the like.
+ See [the documentation](https://docs.rs/structopt/0.3/structopt/#help-messages).
+
+ **HUGE THANKS to [`@ssokolow`](https://github.com/ssokolow)** for tidying up our documentation,
+ teaching me English and explaining why our doc used to suck. I promise I'll make the rest
+ of the doc up to your standards... sometime later!
+
+## New features
+
+* Implement `StructOpt` for `Box<impl StructOpt>` so from now on you can use `Box<T>`
+ with `flatten` and `subcommand` ([#304](https://github.com/TeXitoi/structopt/issues/304)).
+
+ ```rust
+ enum Command {
+ #[structopt(name = "version")]
+ PrintVersion,
+
+ #[structopt(name = "second")]
+ DoSomething {
+ #[structopt(flatten)]
+ config: Box<DoSomethingConfig>,
+ },
+
+ #[structopt(name = "first")]
+ DoSomethingElse {
+ #[structopt(flatten)]
+ config: Box<DoSomethingElseConfig>,
+ }
+ }
+ ```
+
+* Introduced `#[structopt(verbatim_doc_comment)]` attribute that keeps line breaks in
+ doc comments, see
+ [the documentation](https://docs.rs/structopt/0.3/structopt/#doc-comment-preprocessing-and-structoptverbatim_doc_comment).
+
+* Introduced `#[structopt(rename_all_env)]` and `#[structopt(env)]` magical methods
+ so you can derive env var's name from field's name. See
+ [the documentation](https://docs.rs/structopt/0.3/structopt/#auto-deriving-environment-variables).
+
+## Improvements
+
+* Now we have nice README for our examples,
+ [check it out](https://github.com/TeXitoi/structopt/tree/master/examples)!
+
+* Some error messages were improved and clarified, thanks for all people involved!
+
+
+# v0.3.5 (2019-11-22)
+
+* `try_from_str` functions are now called with a `&str` instead of a `&String` ([#282](https://github.com/TeXitoi/structopt/pull/282))
+
+# v0.3.4 (2019-11-08)
+
+* `rename_all` does not apply to fields that were annotated with explicit
+ `short/long/name = "..."` anymore ([#265](https://github.com/TeXitoi/structopt/issues/265))
+* Now raw idents are handled correctly ([#269](https://github.com/TeXitoi/structopt/issues/269))
+* Some documentation improvements and clarification.
+
+# v0.3.3 (2019-10-10)
+
+* Add `from_flag` custom parser to create flags from non-bool types.
+ Fixes [#185](https://github.com/TeXitoi/structopt/issues/185)
+
+# v0.3.2 (2019-09-18)
+
+* `structopt` does not replace `:` with `, ` inside "author" strings while inside `<...>`.
+ Fixes [#156](https://github.com/TeXitoi/structopt/issues/156)
+* Introduced [`#[structopt(skip = expr)]` syntax](https://docs.rs/structopt/0.3.2/structopt/#skipping-fields).
+
+# v0.3.1 (2019-09-06)
+
+* Fix error messages ([#241](https://github.com/TeXitoi/structopt/issues/241))
+* Fix "`skip` plus long doc comment" bug ([#245](https://github.com/TeXitoi/structopt/issues/245))
+* Now `structopt` emits dummy `StructOpt` implementation along with an error. It suppresses
+ meaningless errors like `from_args method is not found for Opt`
+* `.version()` not get generated if `CARGO_PKG_VERSION` is not set anymore.
+
+# v0.3.0 (2019-08-30)
+
+## Breaking changes
+
+### Bump minimum rustc version to 1.36 by [@TeXitoi](https://github.com/TeXitoi)
+Now `rustc` 1.36 is the minimum compiler version supported by `structopt`,
+it likely won't work with older compilers.
+
+### Remove "nightly" feature
+Once upon a time this feature had been used to enable some of improvements
+in `proc-macro2` crate that were available only on nightly. Nowadays this feature doesn't
+mean anything so it's now removed.
+
+### Support optional vectors of arguments for distinguishing between `-o 1 2`, `-o` and no option provided at all by [@sphynx](https://github.com/sphynx) ([#180](https://github.com/TeXitoi/structopt/issues/188)).
+
+```rust
+#[derive(StructOpt)]
+struct Opt {
+ #[structopt(long)]
+ fruit: Option<Vec<String>>,
+}
+
+fn main() {
+ assert_eq!(Opt::from_args(&["test"]), None);
+ assert_eq!(Opt::from_args(&["test", "--fruit"]), Some(vec![]));
+ assert_eq!(Opt::from_args(&["test", "--fruit=apple orange"]), Some(vec!["apple", "orange"]));
+}
+```
+
+If you need to fall back to the old behavior you can use a type alias:
+```rust
+type Something = Vec<String>;
+
+#[derive(StructOpt)]
+struct Opt {
+ #[structopt(long)]
+ fruit: Option<Something>,
+}
+```
+
+### Change default case from 'Verbatim' into 'Kebab' by [@0ndorio](https://github.com/0ndorio) ([#202](https://github.com/TeXitoi/structopt/issues/202)).
+`structopt` 0.3 uses field renaming to deduce a name for long options and subcommands.
+
+```rust
+#[derive(StructOpt)]
+struct Opt {
+ #[structopt(long)]
+ http_addr: String, // will be renamed to `--http-addr`
+
+ #[structopt(subcommand)]
+ addr_type: AddrType // this adds `addr-type` subcommand
+}
+```
+
+`structopt` 0.2 used to leave things "as is", not renaming anything. If you want to keep old
+behavior add `#[structopt(rename_all = "verbatim")]` on top of a `struct`/`enum`.
+
+### Change `version`, `author` and `about` attributes behavior.
+Proposed by [@TeXitoi](https://github.com/TeXitoi) [(#217)](https://github.com/TeXitoi/structopt/issues/217), implemented by [@CreepySkeleton](https://github.com/CreepySkeleton) [(#229)](https://github.com/TeXitoi/structopt/pull/229).
+
+`structopt` have been deducing `version`, `author`, and `about` properties from `Cargo.toml`
+for a long time (more accurately, from `CARGO_PKG_...` environment variables).
+But many users found this behavior somewhat confusing, and a hack was added to cancel out
+this behavior: `#[structopt(author = "")]`.
+
+In `structopt` 0.3 this has changed.
+* `author` and `about` are no longer deduced by default. You should use `#[structopt(author, about)]`
+ to explicitly request `structopt` to deduce them.
+* Contrary, `version` **is still deduced by default**. You can use `#[structopt(no_version)]` to
+ cancel it out.
+* `#[structopt(author = "", about = "", version = "")]` is no longer a valid syntax
+ and will trigger an error.
+* `#[structopt(version = "version", author = "author", about = "about")]` syntax
+ stays unaffected by this changes.
+
+### Raw attributes are removed ([#198](https://github.com/TeXitoi/structopt/pull/198)) by [@sphynx](https://github.com/sphynx)
+In `structopt` 0.2 you were able to use any method from `clap::App` and `clap::Arg` via
+raw attribute: `#[structopt(raw(method_name = "arg"))]`. This syntax was kind of awkward.
+
+```rust
+#[derive(StructOpt, Debug)]
+#[structopt(raw(
+ global_settings = "&[AppSettings::ColoredHelp, AppSettings::VersionlessSubcommands]"
+))]
+struct Opt {
+ #[structopt(short = "l", long = "level", raw(aliases = r#"&["set-level", "lvl"]"#))]
+ level: Vec<String>,
+}
+```
+
+Raw attributes were removed in 0.3. Now you can use any method from `App` and `Arg` *directly*:
+```rust
+#[derive(StructOpt)]
+#[structopt(global_settings(&[AppSettings::ColoredHelp, AppSettings::VersionlessSubcommands]))]
+struct Opt {
+ #[structopt(short = "l", long = "level", aliases(&["set-level", "lvl"]))]
+ level: Vec<String>,
+}
+```
+
+## Improvements
+
+### Support skipping struct fields
+Proposed by [@Morganamilo](https://github.com/Morganamilo) in ([#174](https://github.com/TeXitoi/structopt/issues/174))
+implemented by [@sphynx](https://github.com/sphynx) in ([#213](https://github.com/TeXitoi/structopt/issues/213)).
+
+Sometimes you want to include some fields in your `StructOpt` `struct` that are not options
+and `clap` should know nothing about them. In `structopt` 0.3 it's possible via the
+`#[structopt(skip)]` attribute. The field in question will be assigned with `Default::default()`
+value.
+
+```rust
+#[derive(StructOpt)]
+struct Opt {
+ #[structopt(short, long)]
+ speed: f32,
+
+ car: String,
+
+ // this field should not generate any arguments
+ #[structopt(skip)]
+ meta: Vec<u64>
+}
+```
+
+### Add optional feature to support `paw` by [@gameldar](https://github.com/gameldar) ([#187](https://github.com/TeXitoi/structopt/issues/187))
+
+### Significantly improve error reporting by [@CreepySkeleton](https://github.com/CreepySkeleton) ([#225](https://github.com/TeXitoi/structopt/pull/225/))
+Now (almost) every error message points to the location it originates from:
+
+```text
+error: default_value is meaningless for bool
+ --> $DIR/bool_default_value.rs:14:24
+ |
+14 | #[structopt(short, default_value = true)]
+ | ^^^^^^^^^^^^^
+```
+
+# v0.2.16 (2019-05-29)
+
+### Support optional options with optional argument, allowing `cmd [--opt[=value]]` by [@sphynx](https://github.com/sphynx) ([#188](https://github.com/TeXitoi/structopt/issues/188))
+Sometimes you want to represent an optional option that optionally takes an argument,
+i.e `[--opt[=value]]`. This is represented by `Option<Option<T>>`
+
+```rust
+#[derive(StructOpt)]
+struct Opt {
+ #[structopt(long)]
+ fruit: Option<Option<String>>,
+}
+
+fn main() {
+ assert_eq!(Opt::from_args(&["test"]), None);
+ assert_eq!(Opt::from_args(&["test", "--fruit"]), Some(None));
+ assert_eq!(Opt::from_args(&["test", "--fruit=apple"]), Some("apple"));
+}
+```
+
+# v0.2.15 (2019-03-08)
+
+* Fix [#168](https://github.com/TeXitoi/structopt/issues/168) by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.2.14 (2018-12-10)
+
+* Introduce smarter parsing of doc comments by [@0ndorio](https://github.com/0ndorio)
+
+# v0.2.13 (2018-11-01)
+
+* Automatic naming of fields and subcommands by [@0ndorio](https://github.com/0ndorio)
+
+# v0.2.12 (2018-10-11)
+
+* Fix minimal clap version by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.2.11 (2018-10-05)
+
+* Upgrade syn to 0.15 by [@konstin](https://github.com/konstin)
+
+# v0.2.10 (2018-06-07)
+
+* 1.21.0 is the minimum required rustc version by
+ [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.2.9 (2018-06-05)
+
+* Fix a bug when using `flatten` by
+ [@fbenkstein](https://github.com/fbenkstein)
+* Update syn, quote and proc_macro2 by
+ [@TeXitoi](https://github.com/TeXitoi)
+* Fix a regression when there is multiple authors by
+ [@windwardly](https://github.com/windwardly)
+
+# v0.2.8 (2018-04-28)
+
+* Add `StructOpt::from_iter_safe()`, which returns an `Error` instead of
+ killing the program when it fails to parse, or parses one of the
+ short-circuiting flags. ([#98](https://github.com/TeXitoi/structopt/pull/98)
+ by [@quodlibetor](https://github.com/quodlibetor))
+* Allow users to enable `clap` features independently by
+ [@Kerollmops](https://github.com/Kerollmops)
+* Fix a bug when flattening an enum
+ ([#103](https://github.com/TeXitoi/structopt/pull/103) by
+ [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.2.7 (2018-04-12)
+
+* Add flattening, the insertion of options of another StructOpt struct
+ into another ([#92](https://github.com/TeXitoi/structopt/pull/92))
+ by [@birkenfeld](https://github.com/birkenfeld)
+* Fail compilation when using `default_value` or `required` with
+ `Option` ([#88](https://github.com/TeXitoi/structopt/pull/88)) by
+ [@Kerollmops](https://github.com/Kerollmops)
+
+# v0.2.6 (2018-03-31)
+
+* Fail compilation when using `default_value` or `required` with `bool` ([#80](https://github.com/TeXitoi/structopt/issues/80)) by [@TeXitoi](https://github.com/TeXitoi)
+* Fix compilation with `#[deny(warnings)]` with the `!` type (https://github.com/rust-lang/rust/pull/49039#issuecomment-376398999) by [@TeXitoi](https://github.com/TeXitoi)
+* Improve first example in the documentation ([#82](https://github.com/TeXitoi/structopt/issues/82)) by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.2.5 (2018-03-07)
+
+* Work around breakage when `proc-macro2`'s nightly feature is enabled. ([#77](https://github.com/Texitoi/structopt/pull/77) and [proc-macro2#67](https://github.com/alexcrichton/proc-macro2/issues/67)) by [@fitzgen](https://github.com/fitzgen)
+
+# v0.2.4 (2018-02-25)
+
+* Fix compilation with `#![deny(missig_docs]` ([#74](https://github.com/TeXitoi/structopt/issues/74)) by [@TeXitoi](https://github.com/TeXitoi)
+* Fix [#76](https://github.com/TeXitoi/structopt/issues/76) by [@TeXitoi](https://github.com/TeXitoi)
+* Re-licensed to Apache-2.0/MIT by [@CAD97](https://github.com/cad97)
+
+# v0.2.3 (2018-02-16)
+
+* An empty line in a doc comment will result in a double linefeed in the generated about/help call by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.2.2 (2018-02-12)
+
+* Fix [#66](https://github.com/TeXitoi/structopt/issues/66) by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.2.1 (2018-02-11)
+
+* Fix a bug around enum tuple and the about message in the global help by [@TeXitoi](https://github.com/TeXitoi)
+* Fix [#65](https://github.com/TeXitoi/structopt/issues/65) by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.2.0 (2018-02-10)
+
+## Breaking changes
+
+### Don't special case `u64` by [@SergioBenitez](https://github.com/SergioBenitez)
+
+If you are using a `u64` in your struct to get the number of occurence of a flag, you should now add `parse(from_occurrences)` on the flag.
+
+For example
+```rust
+#[structopt(short = "v", long = "verbose")]
+verbose: u64,
+```
+must be changed by
+```rust
+#[structopt(short = "v", long = "verbose", parse(from_occurrences))]
+verbose: u64,
+```
+
+This feature was surprising as shown in [#30](https://github.com/TeXitoi/structopt/issues/30). Using the `parse` feature seems much more natural.
+
+### Change the signature of `Structopt::from_clap` to take its argument by reference by [@TeXitoi](https://github.com/TeXitoi)
+
+There was no reason to take the argument by value. Most of the StructOpt users will not be impacted by this change. If you are using `StructOpt::from_clap`, just add a `&` before the argument.
+
+### Fail if attributes are not used by [@TeXitoi](https://github.com/TeXitoi)
+
+StructOpt was quite fuzzy in its attribute parsing: it was only searching for interresting things, e. g. something like `#[structopt(foo(bar))]` was accepted but not used. It now fails the compilation.
+
+You should have nothing to do here. This breaking change may highlight some missuse that can be bugs.
+
+In future versions, if there is cases that are not highlighed, they will be considerated as bugs, not breaking changes.
+
+### Use `raw()` wrapping instead of `_raw` suffixing by [@TeXitoi](https://github.com/TeXitoi)
+
+The syntax of raw attributes is changed to improve the syntax.
+
+You have to change `foo_raw = "bar", baz_raw = "foo"` by `raw(foo = "bar", baz = "foo")` or `raw(foo = "bar"), raw(baz = "foo")`.
+
+## New features
+
+* Add `parse(from_occurrences)` parser by [@SergioBenitez](https://github.com/SergioBenitez)
+* Support 1-uple enum variant as subcommand by [@TeXitoi](https://github.com/TeXitoi)
+* structopt-derive crate is now an implementation detail, structopt reexport the custom derive macro by [@TeXitoi](https://github.com/TeXitoi)
+* Add the `StructOpt::from_iter` method by [@Kerollmops](https://github.com/Kerollmops)
+
+## Documentation
+
+* Improve doc by [@bestouff](https://github.com/bestouff)
+* All the documentation is now on the structopt crate by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.1.7 (2018-01-23)
+
+* Allow opting out of clap default features by [@ski-csis](https://github.com/ski-csis)
+
+# v0.1.6 (2017-11-25)
+
+* Improve documentation by [@TeXitoi](https://github.com/TeXitoi)
+* Fix bug [#31](https://github.com/TeXitoi/structopt/issues/31) by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.1.5 (2017-11-14)
+
+* Fix a bug with optional subsubcommand and Enum by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.1.4 (2017-11-09)
+
+* Implement custom string parser from either `&str` or `&OsStr` by [@kennytm](https://github.com/kennytm)
+
+# v0.1.3 (2017-11-01)
+
+* Improve doc by [@TeXitoi](https://github.com/TeXitoi)
+
+# v0.1.2 (2017-11-01)
+
+* Fix bugs [#24](https://github.com/TeXitoi/structopt/issues/24) and [#25](https://github.com/TeXitoi/structopt/issues/25) by [@TeXitoi](https://github.com/TeXitoi)
+* Support of methods with something else that a string as argument thanks to `_raw` suffix by [@Flakebi](https://github.com/Flakebi)
+
+# v0.1.1 (2017-09-22)
+
+* Better formating of multiple authors by [@killercup](https://github.com/killercup)
+
+# v0.1.0 (2017-07-17)
+
+* Subcommand support by [@williamyaoh](https://github.com/williamyaoh)
+
+# v0.0.5 (2017-06-16)
+
+* Using doc comment to populate help by [@killercup](https://github.com/killercup)
+
+# v0.0.3 (2017-02-11)
+
+* First version with flags, arguments and options support by [@TeXitoi](https://github.com/TeXitoi)
diff --git a/structopt/Cargo.toml b/structopt/Cargo.toml
new file mode 100644
index 0000000..b43728b
--- /dev/null
+++ b/structopt/Cargo.toml
@@ -0,0 +1,35 @@
+[package]
+name = "structopt"
+version = "0.3.7"
+edition = "2018"
+authors = ["Guillaume Pinot <texitoi@texitoi.eu>", "others"]
+description = "Parse command line argument by defining a struct."
+documentation = "https://docs.rs/structopt"
+repository = "https://github.com/TeXitoi/structopt"
+keywords = ["clap", "cli", "derive", "docopt"]
+categories = ["command-line-interface"]
+license = "Apache-2.0/MIT"
+readme = "README.md"
+
+[features]
+default = ["clap/default"]
+suggestions = ["clap/suggestions"]
+color = ["clap/color"]
+wrap_help = ["clap/wrap_help"]
+yaml = ["clap/yaml"]
+lints = ["clap/lints"]
+debug = ["clap/debug"]
+no_cargo = ["clap/no_cargo"]
+doc = ["clap/doc"]
+paw = ["structopt-derive/paw"]
+
+[badges]
+travis-ci = { repository = "TeXitoi/structopt" }
+
+[dependencies]
+clap = { version = "2.33", default-features = false }
+structopt-derive = { path = "structopt-derive", version = "=0.4.0" }
+
+[dev-dependencies]
+trybuild = "1.0.5"
+rustversion = "1"
diff --git a/structopt/LICENSE-APACHE b/structopt/LICENSE-APACHE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/structopt/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/structopt/LICENSE-MIT b/structopt/LICENSE-MIT
new file mode 100644
index 0000000..e931b83
--- /dev/null
+++ b/structopt/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+
+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/structopt/README.md b/structopt/README.md
new file mode 100644
index 0000000..48ac3c3
--- /dev/null
+++ b/structopt/README.md
@@ -0,0 +1,148 @@
+# StructOpt [![Build status](https://travis-ci.org/TeXitoi/structopt.svg?branch=master)](https://travis-ci.org/TeXitoi/structopt) [![](https://img.shields.io/crates/v/structopt.svg)](https://crates.io/crates/structopt) [![](https://docs.rs/structopt/badge.svg)](https://docs.rs/structopt)
+
+Parse command line arguments by defining a struct. It combines [clap](https://crates.io/crates/clap) with custom derive.
+
+## Documentation
+
+Find it on [Docs.rs](https://docs.rs/structopt). You can also check the [examples](https://github.com/TeXitoi/structopt/tree/master/examples) and the [changelog](https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md).
+
+## Example
+
+Add `structopt` to your dependencies of your `Cargo.toml`:
+```toml
+[dependencies]
+structopt = "0.3"
+```
+
+And then, in your rust file:
+```rust
+use std::path::PathBuf;
+use structopt::StructOpt;
+
+/// A basic example
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ // A flag, true if used in the command line. Note doc comment will
+ // be used for the help message of the flag. The name of the
+ // argument will be, by default, based on the name of the field.
+ /// Activate debug mode
+ #[structopt(short, long)]
+ debug: bool,
+
+ // The number of occurrences of the `v/verbose` flag
+ /// Verbose mode (-v, -vv, -vvv, etc.)
+ #[structopt(short, long, parse(from_occurrences))]
+ verbose: u8,
+
+ /// Set speed
+ #[structopt(short, long, default_value = "42")]
+ speed: f64,
+
+ /// Output file
+ #[structopt(short, long, parse(from_os_str))]
+ output: PathBuf,
+
+ // the long option will be translated by default to kebab case,
+ // i.e. `--nb-cars`.
+ /// Number of cars
+ #[structopt(short = "c", long)]
+ nb_cars: Option<i32>,
+
+ /// admin_level to consider
+ #[structopt(short, long)]
+ level: Vec<String>,
+
+ /// Files to process
+ #[structopt(name = "FILE", parse(from_os_str))]
+ files: Vec<PathBuf>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:#?}", opt);
+}
+```
+
+Using this example:
+```
+$ ./basic
+error: The following required arguments were not provided:
+ --output <output>
+
+USAGE:
+ basic --output <output> --speed <speed>
+
+For more information try --help
+$ ./basic --help
+basic 0.3.0
+Guillaume Pinot <texitoi@texitoi.eu>, others
+A basic example
+
+USAGE:
+ basic [FLAGS] [OPTIONS] --output <output> [--] [file]...
+
+FLAGS:
+ -d, --debug Activate debug mode
+ -h, --help Prints help information
+ -V, --version Prints version information
+ -v, --verbose Verbose mode (-v, -vv, -vvv, etc.)
+
+OPTIONS:
+ -l, --level <level>... admin_level to consider
+ -c, --nb-cars <nb-cars> Number of cars
+ -o, --output <output> Output file
+ -s, --speed <speed> Set speed [default: 42]
+
+ARGS:
+ <file>... Files to process
+$ ./basic -o foo.txt
+Opt {
+ debug: false,
+ verbose: 0,
+ speed: 42.0,
+ output: "foo.txt",
+ nb_cars: None,
+ level: [],
+ files: [],
+}
+$ ./basic -o foo.txt -dvvvs 1337 -l alice -l bob --nb-cars 4 bar.txt baz.txt
+Opt {
+ debug: true,
+ verbose: 3,
+ speed: 1337.0,
+ output: "foo.txt",
+ nb_cars: Some(
+ 4,
+ ),
+ level: [
+ "alice",
+ "bob",
+ ],
+ files: [
+ "bar.txt",
+ "baz.txt",
+ ],
+}
+```
+
+## StructOpt rustc version policy
+
+- Minimum rustc version modification must be specified in the [changelog](https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md) and in the [travis configuration](https://github.com/TeXitoi/structopt/blob/master/.travis.yml).
+- Contributors can increment minimum rustc version without any justification if the new version is required by the latest version of one of StructOpt's dependencies (`cargo update` will not fail on StructOpt).
+- Contributors can increment minimum rustc version if the library user experience is improved.
+
+## License
+
+Licensed under either of
+
+- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
+- MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
diff --git a/structopt/examples/README.md b/structopt/examples/README.md
new file mode 100644
index 0000000..f0db20b
--- /dev/null
+++ b/structopt/examples/README.md
@@ -0,0 +1,82 @@
+# Collection of examples "how to use `structopt`"
+
+### [Help on the bottom](after_help.rs)
+
+How to append a postscript to the help message generated.
+
+### [At least N](at_least_two.rs)
+
+How to require presence of at least N values, like `val1 val2 ... valN ... valM`.
+
+### [Basic](basic.rs)
+
+A basic example how to use `structopt`.
+
+### [Deny missing docs](deny_missing_docs.rs)
+
+**This is not an example but a test**, it should be moved to `tests` folder
+as soon as [this](https://github.com/rust-lang/rust/issues/24584) is fixed (if ever).
+
+### [Doc comments](doc_comments.rs)
+
+How to use doc comments in place of `help/long_help`.
+
+### [Enums as arguments](enum_in_args.rs)
+
+How to use `arg_enum!` with `StructOpt`.
+
+### [Arguments of subcommands in separate `struct`](enum_tuple.rs)
+
+How to extract subcommands' args into external structs.
+
+### [Environment variables](env.rs)
+
+How to use environment variable fallback an how it interacts with `default_value`.
+
+### [Advanced](example.rs)
+
+Somewhat complex example of usage of `structopt`.
+
+### [Flatten](flatten.rs)
+
+How to use `#[structopt(flatten)]`
+
+### [`bash` completions](gen_completions.rs)
+
+Generating `bash` completions with `structopt`.
+
+### [Git](git.rs)
+
+Pseudo-`git` example, shows how to use subcommands and how to document them.
+
+### [Groups](group.rs)
+
+Using `clap::Arg::group` with `structopt`.
+
+### [`key=value` pairs](keyvalue.rs)
+
+How to parse `key=value` pairs.
+
+### [`--no-*` flags](negative_flag.rs)
+
+How to add `no-thing` flag which is `true` by default and `false` if passed.
+
+### [No version](no_version.rs)
+
+How to completely remove version.
+
+### [Rename all](rename_all.rs)
+
+How `#[structopt(rename_all)]` works.
+
+### [Skip](skip.rs)
+
+How to use `#[structopt(skip)]`.
+
+### [Aliases](subcommand_aliases.rs)
+
+How to use aliases
+
+### [`true` or `false`](true_or_false.rs)
+
+How to express "`"true"` or `"false"` argument.
diff --git a/structopt/examples/after_help.rs b/structopt/examples/after_help.rs
new file mode 100644
index 0000000..db2845f
--- /dev/null
+++ b/structopt/examples/after_help.rs
@@ -0,0 +1,19 @@
+//! How to append a postscript to the help message generated.
+
+use structopt::StructOpt;
+
+/// I am a program and I do things.
+///
+/// Sometimes they even work.
+#[derive(StructOpt, Debug)]
+#[structopt(after_help = "Beware `-d`, dragons be here")]
+struct Opt {
+ /// Release the dragon.
+ #[structopt(short)]
+ dragon: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/at_least_two.rs b/structopt/examples/at_least_two.rs
new file mode 100644
index 0000000..683db50
--- /dev/null
+++ b/structopt/examples/at_least_two.rs
@@ -0,0 +1,15 @@
+//! How to require presence of at least N values,
+//! like `val1 val2 ... valN ... valM`.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+ #[structopt(required = true, min_values = 2)]
+ foos: Vec<String>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/basic.rs b/structopt/examples/basic.rs
new file mode 100644
index 0000000..510e0e0
--- /dev/null
+++ b/structopt/examples/basic.rs
@@ -0,0 +1,48 @@
+//! A somewhat comprehensive example of a typical `StructOpt` usage.use
+
+use std::path::PathBuf;
+use structopt::StructOpt;
+
+/// A basic example
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ // A flag, true if used in the command line. Note doc comment will
+ // be used for the help message of the flag. The name of the
+ // argument will be, by default, based on the name of the field.
+ /// Activate debug mode
+ #[structopt(short, long)]
+ debug: bool,
+
+ // The number of occurrences of the `v/verbose` flag
+ /// Verbose mode (-v, -vv, -vvv, etc.)
+ #[structopt(short, long, parse(from_occurrences))]
+ verbose: u8,
+
+ /// Set speed
+ #[structopt(short, long, default_value = "42")]
+ speed: f64,
+
+ /// Output file
+ #[structopt(short, long, parse(from_os_str))]
+ output: PathBuf,
+
+ // the long option will be translated by default to kebab case,
+ // i.e. `--nb-cars`.
+ /// Number of cars
+ #[structopt(short = "c", long)]
+ nb_cars: Option<i32>,
+
+ /// admin_level to consider
+ #[structopt(short, long)]
+ level: Vec<String>,
+
+ /// Files to process
+ #[structopt(name = "FILE", parse(from_os_str))]
+ files: Vec<PathBuf>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:#?}", opt);
+}
diff --git a/structopt/examples/deny_missing_docs.rs b/structopt/examples/deny_missing_docs.rs
new file mode 100644
index 0000000..82b1e63
--- /dev/null
+++ b/structopt/examples/deny_missing_docs.rs
@@ -0,0 +1,51 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This should be in tests but it will not work until
+// https://github.com/rust-lang/rust/issues/24584 is fixed
+
+//! A test to check that structopt compiles with deny(missing_docs)
+
+#![deny(missing_docs)]
+
+use structopt::StructOpt;
+
+/// The options
+#[derive(StructOpt, Debug, PartialEq)]
+pub struct Opt {
+ #[structopt(short)]
+ verbose: bool,
+ #[structopt(subcommand)]
+ cmd: Option<Cmd>,
+}
+
+/// Some subcommands
+#[derive(StructOpt, Debug, PartialEq)]
+pub enum Cmd {
+ /// command A
+ A,
+ /// command B
+ B {
+ /// Alice?
+ #[structopt(short)]
+ alice: bool,
+ },
+ /// command C
+ C(COpt),
+}
+
+/// The options for C
+#[derive(StructOpt, Debug, PartialEq)]
+pub struct COpt {
+ #[structopt(short)]
+ bob: bool,
+}
+
+fn main() {
+ println!("{:?}", Opt::from_args());
+}
diff --git a/structopt/examples/doc_comments.rs b/structopt/examples/doc_comments.rs
new file mode 100644
index 0000000..810101f
--- /dev/null
+++ b/structopt/examples/doc_comments.rs
@@ -0,0 +1,74 @@
+//! How to use doc comments in place of `help/long_help`.
+
+use structopt::StructOpt;
+
+/// A basic example for the usage of doc comments as replacement
+/// of the arguments `help`, `long_help`, `about` and `long_about`.
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ /// Just use doc comments to replace `help`, `long_help`,
+ /// `about` or `long_about` input.
+ #[structopt(short, long)]
+ first_flag: bool,
+
+ /// Split between `help` and `long_help`.
+ ///
+ /// In the previous case structopt is going to present
+ /// the whole comment both as text for the `help` and the
+ /// `long_help` argument.
+ ///
+ /// But if the doc comment is formatted like this example
+ /// -- with an empty second line splitting the heading and
+ /// the rest of the comment -- only the first line is used
+ /// as `help` argument. The `long_help` argument will still
+ /// contain the whole comment.
+ ///
+ /// ## Attention
+ ///
+ /// Any formatting next to empty lines that could be used
+ /// inside a doc comment is currently not preserved. If
+ /// lists or other well formatted content is required it is
+ /// necessary to use the related structopt argument with a
+ /// raw string as shown on the `third_flag` description.
+ #[structopt(short, long)]
+ second_flag: bool,
+
+ #[structopt(
+ short,
+ long,
+ long_help = r"This is a raw string.
+
+It can be used to pass well formatted content (e.g. lists or source
+code) in the description:
+
+ - first example list entry
+ - second example list entry
+ "
+ )]
+ third_flag: bool,
+
+ #[structopt(subcommand)]
+ sub_command: SubCommand,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt()]
+enum SubCommand {
+ /// The same rules described previously for flags. Are
+ /// also true for in regards of sub-commands.
+ First,
+
+ /// Applicable for both `about` an `help`.
+ ///
+ /// The formatting rules described in the comment of the
+ /// `second_flag` also apply to the description of
+ /// sub-commands which is normally given through the `about`
+ /// and `long_about` arguments.
+ Second,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/enum_in_args.rs b/structopt/examples/enum_in_args.rs
new file mode 100644
index 0000000..70347da
--- /dev/null
+++ b/structopt/examples/enum_in_args.rs
@@ -0,0 +1,25 @@
+//! How to use `arg_enum!` with `StructOpt`.
+
+use clap::arg_enum;
+use structopt::StructOpt;
+
+arg_enum! {
+ #[derive(Debug)]
+ enum Baz {
+ Foo,
+ Bar,
+ FooBar
+ }
+}
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+ /// Important argument.
+ #[structopt(possible_values = &Baz::variants(), case_insensitive = true)]
+ i: Baz,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/enum_tuple.rs b/structopt/examples/enum_tuple.rs
new file mode 100644
index 0000000..0bad2e6
--- /dev/null
+++ b/structopt/examples/enum_tuple.rs
@@ -0,0 +1,26 @@
+//! How to extract subcommands' args into external structs.
+
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+pub struct Foo {
+ pub bar: Option<String>,
+}
+
+#[derive(Debug, StructOpt)]
+pub enum Command {
+ #[structopt(name = "foo")]
+ Foo(Foo),
+}
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "classify")]
+pub struct ApplicationArguments {
+ #[structopt(subcommand)]
+ pub command: Command,
+}
+
+fn main() {
+ let opt = ApplicationArguments::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/env.rs b/structopt/examples/env.rs
new file mode 100644
index 0000000..0477089
--- /dev/null
+++ b/structopt/examples/env.rs
@@ -0,0 +1,26 @@
+//! How to use environment variable fallback an how it
+//! interacts with `default_value`.
+
+use structopt::StructOpt;
+
+/// Example for allowing to specify options via environment variables.
+#[derive(StructOpt, Debug)]
+#[structopt(name = "env")]
+struct Opt {
+ // Use `env` to enable specifying the option with an environment
+ // variable. Command line arguments take precedence over env.
+ /// URL for the API server
+ #[structopt(long, env = "API_URL")]
+ api_url: String,
+
+ // The default value is used if neither argument nor environment
+ // variable is specified.
+ /// Number of retries
+ #[structopt(long, env = "RETRIES", default_value = "5")]
+ retries: u32,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:#?}", opt);
+}
diff --git a/structopt/examples/example.rs b/structopt/examples/example.rs
new file mode 100644
index 0000000..7a9a514
--- /dev/null
+++ b/structopt/examples/example.rs
@@ -0,0 +1,54 @@
+//! Somewhat complex example of usage of structopt.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "example")]
+/// An example of StructOpt usage.
+struct Opt {
+ // A flag, true if used in the command line.
+ #[structopt(short, long)]
+ /// Activate debug mode
+ debug: bool,
+
+ // An argument of type float, with a default value.
+ #[structopt(short, long, default_value = "42")]
+ /// Set speed
+ speed: f64,
+
+ // Needed parameter, the first on the command line.
+ /// Input file
+ input: String,
+
+ // An optional parameter, will be `None` if not present on the
+ // command line.
+ /// Output file, stdout if not present
+ output: Option<String>,
+
+ // An optional parameter with optional value, will be `None` if
+ // not present on the command line, will be `Some(None)` if no
+ // argument is provided (i.e. `--log`) and will be
+ // `Some(Some(String))` if argument is provided (e.g. `--log
+ // log.txt`).
+ #[structopt(long)]
+ #[allow(clippy::option_option)]
+ /// Log file, stdout if no file, no logging if not present
+ log: Option<Option<String>>,
+
+ // An optional list of values, will be `None` if not present on
+ // the command line, will be `Some(vec![])` if no argument is
+ // provided (i.e. `--optv`) and will be `Some(Some(String))` if
+ // argument list is provided (e.g. `--optv a b c`).
+ #[structopt(long)]
+ optv: Option<Vec<String>>,
+
+ // Skipped option: it won't be parsed and will be filled with the
+ // default value for its type (in this case it'll be an empty string).
+ #[structopt(skip)]
+ skipped: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/flatten.rs b/structopt/examples/flatten.rs
new file mode 100644
index 0000000..d51647f
--- /dev/null
+++ b/structopt/examples/flatten.rs
@@ -0,0 +1,29 @@
+//! How to use flattening.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct Cmdline {
+ /// switch verbosity on
+ #[structopt(short)]
+ verbose: bool,
+
+ #[structopt(flatten)]
+ daemon_opts: DaemonOpts,
+}
+
+#[derive(StructOpt, Debug)]
+struct DaemonOpts {
+ /// daemon user
+ #[structopt(short)]
+ user: String,
+
+ /// daemon group
+ #[structopt(short)]
+ group: String,
+}
+
+fn main() {
+ let opt = Cmdline::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/gen_completions.rs b/structopt/examples/gen_completions.rs
new file mode 100644
index 0000000..4f35b07
--- /dev/null
+++ b/structopt/examples/gen_completions.rs
@@ -0,0 +1,26 @@
+// Copyright 2019-present structopt developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::clap::Shell;
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+/// An example of how to generate bash completions with structopt.
+struct Opt {
+ #[structopt(short, long)]
+ /// Activate debug mode
+ debug: bool,
+}
+
+fn main() {
+ // generate `bash` completions in "target" directory
+ Opt::clap().gen_completions(env!("CARGO_PKG_NAME"), Shell::Bash, "target");
+
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/git.rs b/structopt/examples/git.rs
new file mode 100644
index 0000000..494e9d1
--- /dev/null
+++ b/structopt/examples/git.rs
@@ -0,0 +1,35 @@
+//! `git.rs` serves as a demonstration of how to use subcommands,
+//! as well as a demonstration of adding documentation to subcommands.
+//! Documentation can be added either through doc comments or
+//! `help`/`about` attributes.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "git")]
+/// the stupid content tracker
+enum Opt {
+ /// fetch branches from remote repository
+ Fetch {
+ #[structopt(long)]
+ dry_run: bool,
+ #[structopt(long)]
+ all: bool,
+ #[structopt(default_value = "origin")]
+ repository: String,
+ },
+ #[structopt(help = "add files to the staging area")]
+ Add {
+ #[structopt(short)]
+ interactive: bool,
+ #[structopt(short)]
+ all: bool,
+ files: Vec<String>,
+ },
+}
+
+fn main() {
+ let matches = Opt::from_args();
+
+ println!("{:?}", matches);
+}
diff --git a/structopt/examples/group.rs b/structopt/examples/group.rs
new file mode 100644
index 0000000..d53de6a
--- /dev/null
+++ b/structopt/examples/group.rs
@@ -0,0 +1,31 @@
+//! How to use `clap::Arg::group`
+
+use structopt::{clap::ArgGroup, StructOpt};
+
+#[derive(StructOpt, Debug)]
+#[structopt(group = ArgGroup::with_name("verb").required(true))]
+struct Opt {
+ /// Set a custom HTTP verb
+ #[structopt(long, group = "verb")]
+ method: Option<String>,
+ /// HTTP GET
+ #[structopt(long, group = "verb")]
+ get: bool,
+ /// HTTP HEAD
+ #[structopt(long, group = "verb")]
+ head: bool,
+ /// HTTP POST
+ #[structopt(long, group = "verb")]
+ post: bool,
+ /// HTTP PUT
+ #[structopt(long, group = "verb")]
+ put: bool,
+ /// HTTP DELETE
+ #[structopt(long, group = "verb")]
+ delete: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/keyvalue.rs b/structopt/examples/keyvalue.rs
new file mode 100644
index 0000000..12ce6fc
--- /dev/null
+++ b/structopt/examples/keyvalue.rs
@@ -0,0 +1,36 @@
+//! How to parse "key=value" pairs with structopt.
+
+use std::error::Error;
+use structopt::StructOpt;
+
+/// Parse a single key-value pair
+fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error>>
+where
+ T: std::str::FromStr,
+ T::Err: Error + 'static,
+ U: std::str::FromStr,
+ U::Err: Error + 'static,
+{
+ let pos = s
+ .find('=')
+ .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
+ Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
+}
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+ // number_of_values = 1 forces the user to repeat the -D option for each key-value pair:
+ // my_program -D a=1 -D b=2
+ // Without number_of_values = 1 you can do:
+ // my_program -D a=1 b=2
+ // but this makes adding an argument after the values impossible:
+ // my_program -D a=1 -D b=2 my_input_file
+ // becomes invalid.
+ #[structopt(short = "D", parse(try_from_str = parse_key_val), number_of_values = 1)]
+ defines: Vec<(String, i32)>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/negative_flag.rs b/structopt/examples/negative_flag.rs
new file mode 100644
index 0000000..b178bf5
--- /dev/null
+++ b/structopt/examples/negative_flag.rs
@@ -0,0 +1,15 @@
+//! How to add `no-thing` flag which is `true` by default and
+//! `false` if passed.
+
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+struct Opt {
+ #[structopt(long = "no-verbose", parse(from_flag = std::ops::Not::not))]
+ verbose: bool,
+}
+
+fn main() {
+ let cmd = Opt::from_args();
+ println!("{:#?}", cmd);
+}
diff --git a/structopt/examples/no_version.rs b/structopt/examples/no_version.rs
new file mode 100644
index 0000000..a542ec1
--- /dev/null
+++ b/structopt/examples/no_version.rs
@@ -0,0 +1,17 @@
+//! How to completely remove version.
+
+use structopt::clap::AppSettings;
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(
+ name = "no_version",
+ no_version,
+ global_settings = &[AppSettings::DisableVersion]
+)]
+struct Opt {}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/rename_all.rs b/structopt/examples/rename_all.rs
new file mode 100644
index 0000000..35f3c4f
--- /dev/null
+++ b/structopt/examples/rename_all.rs
@@ -0,0 +1,74 @@
+//! Example on how the `rename_all` parameter works.
+//!
+//! `rename_all` can be used to override the casing style used during argument
+//! generation. By default the `kebab-case` style will be used but there are a wide
+//! variety of other styles available.
+//!
+//! ## Supported styles overview:
+//!
+//! - **Camel Case**: Indicate word boundaries with uppercase letter, excluding
+//! the first word.
+//! - **Kebab Case**: Keep all letters lowercase and indicate word boundaries
+//! with hyphens.
+//! - **Pascal Case**: Indicate word boundaries with uppercase letter,
+//! including the first word.
+//! - **Screaming Snake Case**: Keep all letters uppercase and indicate word
+//! boundaries with underscores.
+//! - **Snake Case**: Keep all letters lowercase and indicate word boundaries
+//! with underscores.
+//! - **Verbatim**: Use the original attribute name defined in the code.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "rename_all", rename_all = "screaming_snake_case")]
+enum Opt {
+ // This subcommand will be named `FIRST_COMMAND`. As the command doesn't
+ // override the initial casing style, ...
+ /// A screaming loud first command. Only use if necessary.
+ FirstCommand {
+ // this flag will be available as `--FOO` and `-F`.
+ /// This flag will even scream louder.
+ #[structopt(long, short)]
+ foo: bool,
+ },
+
+ // As we override the casing style for this variant the related subcommand
+ // will be named `SecondCommand`.
+ /// Not nearly as loud as the first command.
+ #[structopt(rename_all = "pascal_case")]
+ SecondCommand {
+ // We can also override it again on a single field.
+ /// Nice quiet flag. No one is annoyed.
+ #[structopt(rename_all = "snake_case", long)]
+ bar_option: bool,
+
+ // Renaming will not be propagated into subcommand flagged enums. If
+ // a non default casing style is required it must be defined on the
+ // enum itself.
+ #[structopt(subcommand)]
+ cmds: Subcommands,
+
+ // or flattened structs.
+ #[structopt(flatten)]
+ options: BonusOptions,
+ },
+}
+
+#[derive(StructOpt, Debug)]
+enum Subcommands {
+ // This one will be available as `first-subcommand`.
+ FirstSubcommand,
+}
+
+#[derive(StructOpt, Debug)]
+struct BonusOptions {
+ // And this one will be available as `baz-option`.
+ #[structopt(long)]
+ baz_option: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/skip.rs b/structopt/examples/skip.rs
new file mode 100644
index 0000000..1f44769
--- /dev/null
+++ b/structopt/examples/skip.rs
@@ -0,0 +1,47 @@
+//! How to use `#[structopt(skip)]`
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug, PartialEq)]
+pub struct Opt {
+ #[structopt(long, short)]
+ number: u32,
+ #[structopt(skip)]
+ k: Kind,
+ #[structopt(skip)]
+ v: Vec<u32>,
+
+ #[structopt(skip = Kind::A)]
+ k2: Kind,
+ #[structopt(skip = vec![1, 2, 3])]
+ v2: Vec<u32>,
+ #[structopt(skip = "cake")] // &str implements Into<String>
+ s: String,
+}
+
+#[derive(Debug, PartialEq)]
+enum Kind {
+ A,
+ B,
+}
+
+impl Default for Kind {
+ fn default() -> Self {
+ return Kind::B;
+ }
+}
+
+fn main() {
+ assert_eq!(
+ Opt::from_iter(&["test", "-n", "10"]),
+ Opt {
+ number: 10,
+ k: Kind::B,
+ v: vec![],
+
+ k2: Kind::A,
+ v2: vec![1, 2, 3],
+ s: String::from("cake")
+ }
+ );
+}
diff --git a/structopt/examples/subcommand_aliases.rs b/structopt/examples/subcommand_aliases.rs
new file mode 100644
index 0000000..30b8cc3
--- /dev/null
+++ b/structopt/examples/subcommand_aliases.rs
@@ -0,0 +1,21 @@
+//! How to assign some aliases to subcommands
+
+use structopt::clap::AppSettings;
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+// https://docs.rs/clap/2/clap/enum.AppSettings.html#variant.InferSubcommands
+#[structopt(setting = AppSettings::InferSubcommands)]
+enum Opt {
+ // https://docs.rs/clap/2/clap/struct.App.html#method.alias
+ #[structopt(alias = "foobar")]
+ Foo,
+ // https://docs.rs/clap/2/clap/struct.App.html#method.aliases
+ #[structopt(aliases = &["baz", "fizz"])]
+ Bar,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/examples/true_or_false.rs b/structopt/examples/true_or_false.rs
new file mode 100644
index 0000000..31a543e
--- /dev/null
+++ b/structopt/examples/true_or_false.rs
@@ -0,0 +1,41 @@
+//! How to parse `--foo=true --bar=false` and turn them into bool.
+
+use structopt::StructOpt;
+
+fn true_or_false(s: &str) -> Result<bool, &'static str> {
+ match s {
+ "true" => Ok(true),
+ "false" => Ok(false),
+ _ => Err("expected `true` or `false`"),
+ }
+}
+
+#[derive(StructOpt, Debug, PartialEq)]
+struct Opt {
+ // Default parser for `try_from_str` is FromStr::from_str.
+ // `impl FromStr for bool` parses `true` or `false` so this
+ // works as expected.
+ #[structopt(long, parse(try_from_str))]
+ foo: bool,
+
+ // Of course, this could be done with an explicit parser function.
+ #[structopt(long, parse(try_from_str = true_or_false))]
+ bar: bool,
+
+ // `bool` can be positional only with explicit `parse(...)` annotation
+ #[structopt(long, parse(try_from_str))]
+ boom: bool,
+}
+
+fn main() {
+ assert_eq!(
+ Opt::from_iter(&["test", "--foo=true", "--bar=false", "true"]),
+ Opt {
+ foo: true,
+ bar: false,
+ boom: true
+ }
+ );
+ // no beauty, only truth and falseness
+ assert!(Opt::from_iter_safe(&["test", "--foo=beauty"]).is_err());
+}
diff --git a/structopt/link-check-headers.json b/structopt/link-check-headers.json
new file mode 100644
index 0000000..c1bb248
--- /dev/null
+++ b/structopt/link-check-headers.json
@@ -0,0 +1,14 @@
+{
+ "httpHeaders": [
+ {
+ "urls": [
+ "https://",
+ "http://"
+ ],
+ "headers": {
+ "User-Agent": "broken links checker (https://github.com/TeXitoi/structopt)",
+ "Accept": "text/html"
+ }
+ }
+ ]
+}
diff --git a/structopt/src/lib.rs b/structopt/src/lib.rs
new file mode 100644
index 0000000..70c0768
--- /dev/null
+++ b/structopt/src/lib.rs
@@ -0,0 +1,1015 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(missing_docs)]
+
+//! This crate defines the `StructOpt` trait and its custom derive.
+//!
+//! ## Features
+//!
+//! If you want to disable all the `clap` features (colors,
+//! suggestions, ..) add `default-features = false` to the `structopt`
+//! dependency:
+//!
+//! ```toml
+//! [dependencies]
+//! structopt = { version = "0.3", default-features = false }
+//! ```
+//!
+//! Support for [`paw`](https://github.com/rust-cli/paw) (the
+//! `Command line argument paw-rser abstraction for main`) is disabled
+//! by default, but can be enabled in the `structopt` dependency
+//! with the feature `paw`:
+//!
+//! ```toml
+//! [dependencies]
+//! structopt = { version = "0.3", features = [ "paw" ] }
+//! paw = "1.0"
+//! ```
+//!
+//! # Table of Contents
+//!
+//! - [How to `derive(StructOpt)`](#how-to-derivestructopt)
+//! - [Attributes](#attributes)
+//! - [Raw methods](#raw-methods)
+//! - [Magical methods](#magical-methods)
+//! - Arguments
+//! - [Type magic](#type-magic)
+//! - [Specifying argument types](#specifying-argument-types)
+//! - [Help messages](#help-messages)
+//! - [Environment variable fallback](#environment-variable-fallback)
+//! - [Skipping fields](#skipping-fields)
+//! - [Subcommands](#subcommands)
+//! - [Optional subcommands](#optional-subcommands)
+//! - [Flattening](#flattening)
+//! - [Custom string parsers](#custom-string-parsers)
+//!
+//!
+//!
+//! ## How to `derive(StructOpt)`
+//!
+//! First, let's look at the example:
+//!
+//! ```should_panic
+//! use std::path::PathBuf;
+//! use structopt::StructOpt;
+//!
+//! #[derive(Debug, StructOpt)]
+//! #[structopt(name = "example", about = "An example of StructOpt usage.")]
+//! struct Opt {
+//! /// Activate debug mode
+//! // short and long flags (-d, --debug) will be deduced from the field's name
+//! #[structopt(short, long)]
+//! debug: bool,
+//!
+//! /// Set speed
+//! // we don't want to name it "speed", need to look smart
+//! #[structopt(short = "v", long = "velocity", default_value = "42")]
+//! speed: f64,
+//!
+//! /// Input file
+//! #[structopt(parse(from_os_str))]
+//! input: PathBuf,
+//!
+//! /// Output file, stdout if not present
+//! #[structopt(parse(from_os_str))]
+//! output: Option<PathBuf>,
+//!
+//! /// Where to write the output: to `stdout` or `file`
+//! #[structopt(short)]
+//! out_type: String,
+//!
+//! /// File name: only required when `out` is set to `file`
+//! #[structopt(name = "FILE", required_if("out_type", "file"))]
+//! file_name: String,
+//! }
+//!
+//! fn main() {
+//! let opt = Opt::from_args();
+//! println!("{:?}", opt);
+//! }
+//! ```
+//!
+//! So `derive(StructOpt)` tells Rust to generate a command line parser,
+//! and the various `structopt` attributes are simply
+//! used for additional parameters.
+//!
+//! First, define a struct, whatever its name. This structure
+//! corresponds to a `clap::App`, its fields correspond to `clap::Arg`
+//! (unless they're [subcommands](#subcommands)),
+//! and you can adjust these apps and args by `#[structopt(...)]` [attributes](#attributes).
+//!
+//! **Note:**
+//! _________________
+//! Keep in mind that `StructOpt` trait is more than just `from_args` method.
+//! It has a number of additional features, including access to underlying
+//! `clap::App` via `StructOpt::clap()`. See the
+//! [trait's reference documentation](trait.StructOpt.html).
+//! _________________
+//!
+//! ## Attributes
+//!
+//! `#[structopt(...)]` attributes fall into two categories:
+//! - `structopt`'s own [magical methods](#magical-methods).
+//!
+//! They are used by `structopt` itself. They come mostly in
+//! `attr = ["whatever"]` form, but some `attr(args...)` also exist.
+//!
+//! - [`raw` attributes](#raw-methods).
+//!
+//! They represent explicit `clap::Arg/App` method calls.
+//! They are what used to be explicit `#[structopt(raw(...))]` attrs in pre-0.3 `structopt`
+//!
+//! Every `structopt attribute` looks like comma-separated sequence of methods:
+//! ```rust,ignore
+//! #[structopt(
+//! short, // method with no arguments - always magical
+//! long = "--long-option", // method with one argument
+//! required_if("out", "file"), // method with one and more args
+//! parse(from_os_str = path::to::parser) // some magical methods have their own syntax
+//! )]
+//! ```
+//!
+//! `#[structopt(...)]` attributes can be placed on top of `struct`, `enum`,
+//! `struct` field or `enum` variant. Attributes on top of `struct` or `enum`
+//! represent `clap::App` method calls, field or variant attributes correspond
+//! to `clap::Arg` method calls.
+//!
+//! In other words, the `Opt` struct from the example above
+//! will be turned into this (*details omitted*):
+//!
+//! ```
+//! # use structopt::clap::{Arg, App};
+//! App::new("example")
+//! .version("0.2.0")
+//! .about("An example of StructOpt usage.")
+//! .arg(Arg::with_name("debug")
+//! .help("Activate debug mode")
+//! .short("debug")
+//! .long("debug"))
+//! .arg(Arg::with_name("speed")
+//! .help("Set speed")
+//! .short("v")
+//! .long("velocity")
+//! .default_value("42"))
+//! // and so on
+//! # ;
+//! ```
+//!
+//! ## Raw methods
+//!
+//! They are the reason why `structopt` is so flexible.
+//!
+//! Each and every method from `clap::App` and `clap::Arg` can be used directly -
+//! just `#[structopt(method_name = single_arg)]` or `#[structopt(method_name(arg1, arg2))]`
+//! and it just works. As long as `method_name` is not one of the magical methods -
+//! it's just a method call.
+//!
+//! **Note:**
+//! _________________
+//!
+//! "Raw methods" are direct replacement for pre-0.3 structopt's
+//! `#[structopt(raw(...))]` attributes, any time you would have used a `raw()` attribute
+//! in 0.2 you should use raw method in 0.3.
+//!
+//! Unfortunately, old raw attributes collide with `clap::Arg::raw` method. To explicitly
+//! warn users of this change we allow `#[structopt(raw())]` only with `true` or `false`
+//! literals (this method is supposed to be called only with `true` anyway).
+//! __________________
+//!
+//! ## Magical methods
+//!
+//! They are the reason why `structopt` is so easy to use and convenient in most cases.
+//! Many of them have defaults, some of them get used even if not mentioned.
+//!
+//! Methods may be used on "top level" (on top of a `struct`, `enum` or `enum` variant)
+//! and/or on "field-level" (on top of a `struct` field or *inside* of an enum variant).
+//! Top level (non-magical) methods correspond to `App::method` calls, field-level methods
+//! are `Arg::method` calls.
+//!
+//! ```ignore
+//! #[structopt(top_level)]
+//! struct Foo {
+//! #[structopt(field_level)]
+//! field: u32
+//! }
+//!
+//! #[structopt(top_level)]
+//! enum Bar {
+//! #[structopt(top_level)]
+//! Pineapple {
+//! #[structopt(field_level)]
+//! chocolate: String
+//! },
+//!
+//! #[structopt(top_level)]
+//! Orange,
+//! }
+//! ```
+//!
+//! - `name`: `[name = "name"]`
+//! - On top level: `App::new("name")`.
+//!
+//! The binary name displayed in help messages. Defaults to the crate name given by Cargo.
+//!
+//! - On field-level: `Arg::with_name("name")`.
+//!
+//! The name for the argument the field stands for, this name appears in help messages.
+//! Defaults to a name, deduced from a field, see also
+//! [`rename_all`](#specifying-argument-types).
+//!
+//! - `version`: `[version = "version"]`
+//!
+//! Usable only on top level: `App::version("version" or env!(CARGO_PKG_VERSION))`.
+//!
+//! The version displayed in help messages.
+//! Defaults to the crate version given by Cargo. If `CARGO_PKG_VERSION` is not
+//! set no `.version()` calls will be generated unless requested.
+//!
+//! - `no_version`: `no_version`
+//!
+//! Usable only on top level. Prevents default `App::version` call, i.e
+//! when no `version = "version"` mentioned.
+//!
+//! - `author`: `author [= "author"]`
+//!
+//! Usable only on top level: `App::author("author" or env!(CARGO_PKG_AUTHOR))`.
+//!
+//! Author/maintainer of the binary, this name appears in help messages.
+//! Defaults to the crate author given by cargo, but only when `author` explicitly mentioned.
+//!
+//! - `about`: `about [= "about"]`
+//!
+//! Usable only on top level: `App::about("about" or env!(CARGO_PKG_DESCRIPTION))`.
+//!
+//! Short description of the binary, appears in help messages.
+//! Defaults to the crate description given by cargo,
+//! but only when `about` explicitly mentioned.
+//!
+//! - [`short`](#specifying-argument-types): `short [= "short-opt-name"]`
+//!
+//! Usable only on field-level.
+//!
+//! - [`long`](#specifying-argument-types): `long [= "long-opt-name"]`
+//!
+//! Usable only on field-level.
+//!
+//! - [`rename_all`](#specifying-argument-types): [`rename_all = "kebab"/"snake"/"screaming-snake"/"camel"/"pascal"/"verbatim"]`
+//!
+//! Usable both on top level and field level.
+//!
+//! - [`parse`](#custom-string-parsers): `parse(type [= path::to::parser::fn])`
+//!
+//! Usable only on field-level.
+//!
+//! - [`skip`](#skipping-fields): `skip [= expr]`
+//!
+//! Usable only on field-level.
+//!
+//! - [`flatten`](#flattening): `flatten`
+//!
+//! Usable only on field-level.
+//!
+//! - [`subcommand`](#subcommands): `subcommand`
+//!
+//! Usable only on field-level.
+//!
+//! - [`env`](#environment-variable-fallback): `env [= str_literal]`
+//!
+//! Usable only on field-level.
+//!
+//! - [`rename_all_env`](##auto-deriving-environment-variables): [`rename_all_env = "kebab"/"snake"/"screaming-snake"/"camel"/"pascal"/"verbatim"]`
+//!
+//! Usable both on top level and field level.
+//!
+//! - [`verbatim_doc_comment`](#doc-comment-preprocessing-and-structoptverbatim_doc_comment):
+//! `verbatim_doc_comment`
+//!
+//! Usable both on top level and field level.
+//!
+//! ## Type magic
+//!
+//! One of major things that makes `structopt` so awesome is it's type magic.
+//! Do you want optional positional argument? Use `Option<T>`! Or perhaps optional argument
+//! that optionally takes value (`[--opt=[val]]`)? Use `Option<Option<T>>`!
+//!
+//! Here is the table of types and `clap` methods they correspond to:
+//!
+//! Type | Effect | Added method call to `clap::Arg`
+//! -----------------------------|---------------------------------------------------|--------------------------------------
+//! `bool` | `true` if the flag is present | `.takes_value(false).multiple(false)`
+//! `Option<T: FromStr>` | optional positional argument or option | `.takes_value(true).multiple(false)`
+//! `Option<Option<T: FromStr>>` | optional option with optional value | `.takes_value(true).multiple(false).min_values(0).max_values(1)`
+//! `Vec<T: FromStr>` | list of options or the other positional arguments | `.takes_value(true).multiple(true)`
+//! `Option<Vec<T: FromStr>` | optional list of options | `.takes_values(true).multiple(true).min_values(0)`
+//! `T: FromStr` | required option or positional argument | `.takes_value(true).multiple(false).required(!has_default)`
+//!
+//! The `FromStr` trait is used to convert the argument to the given
+//! type, and the `Arg::validator` method is set to a method using
+//! `to_string()` (`FromStr::Err` must implement `std::fmt::Display`).
+//! If you would like to use a custom string parser other than `FromStr`, see
+//! the [same titled section](#custom-string-parsers) below.
+//!
+//! **Note:**
+//! _________________
+//! Pay attention that *only literal occurrence* of this types is special, for example
+//! `Option<T>` is special while `::std::option::Option<T>` is not.
+//!
+//! If you need to avoid special casing you can make a `type` alias and
+//! use it in place of the said type.
+//! _________________
+//!
+//! **Note:**
+//! _________________
+//! `bool` cannot be used as positional argument unless you provide an explicit parser.
+//! If you need a positional bool, for example to parse `true` or `false`, you must
+//! annotate the field with explicit [`#[structopt(parse(...))]`](#custom-string-parsers).
+//! _________________
+//!
+//! Thus, the `speed` argument is generated as:
+//!
+//! ```
+//! # extern crate clap;
+//! # fn parse_validator<T>(_: String) -> Result<(), String> { unimplemented!() }
+//! # fn main() {
+//! clap::Arg::with_name("speed")
+//! .takes_value(true)
+//! .multiple(false)
+//! .required(false)
+//! .validator(parse_validator::<f64>)
+//! .short("v")
+//! .long("velocity")
+//! .help("Set speed")
+//! .default_value("42");
+//! # }
+//! ```
+//!
+//! ## Specifying argument types
+//!
+//! There are three types of arguments that can be supplied to each
+//! (sub-)command:
+//!
+//! - short (e.g. `-h`),
+//! - long (e.g. `--help`)
+//! - and positional.
+//!
+//! Like clap, structopt defaults to creating positional arguments.
+//!
+//! If you want to generate a long argument you can specify either
+//! `long = $NAME`, or just `long` to get a long flag generated using
+//! the field name. The generated casing style can be modified using
+//! the `rename_all` attribute. See the `rename_all` example for more.
+//!
+//! For short arguments, `short` will use the first letter of the
+//! field name by default, but just like the long option it's also
+//! possible to use a custom letter through `short = $LETTER`.
+//!
+//! If an argument is renamed using `name = $NAME` any following call to
+//! `short` or `long` will use the new name.
+//!
+//! **Attention**: If these arguments are used without an explicit name
+//! the resulting flag is going to be renamed using `kebab-case` if the
+//! `rename_all` attribute was not specified previously. The same is true
+//! for subcommands with implicit naming through the related data structure.
+//!
+//! ```
+//! use structopt::StructOpt;
+//!
+//! #[derive(StructOpt)]
+//! #[structopt(rename_all = "kebab-case")]
+//! struct Opt {
+//! /// This option can be specified with something like `--foo-option
+//! /// value` or `--foo-option=value`
+//! #[structopt(long)]
+//! foo_option: String,
+//!
+//! /// This option can be specified with something like `-b value` (but
+//! /// not `--bar-option value`).
+//! #[structopt(short)]
+//! bar_option: String,
+//!
+//! /// This option can be specified either `--baz value` or `-z value`.
+//! #[structopt(short = "z", long = "baz")]
+//! baz_option: String,
+//!
+//! /// This option can be specified either by `--custom value` or
+//! /// `-c value`.
+//! #[structopt(name = "custom", long, short)]
+//! custom_option: String,
+//!
+//! /// This option is positional, meaning it is the first unadorned string
+//! /// you provide (multiple others could follow).
+//! my_positional: String,
+//!
+//! /// This option is skipped and will be filled with the default value
+//! /// for its type (in this case 0).
+//! #[structopt(skip)]
+//! skipped: u32,
+//!
+//! }
+//!
+//! # fn main() {
+//! # Opt::from_clap(&Opt::clap().get_matches_from(
+//! # &["test", "--foo-option", "", "-b", "", "--baz", "", "--custom", "", "positional"]));
+//! # }
+//! ```
+//!
+//! ## Help messages
+//!
+//! In clap, help messages for the whole binary can be specified
+//! via [`App::about`] and [`App::long_about`] while help messages
+//! for individual arguments can be specified via [`Arg::help`] and [`Arg::long_help`]".
+//!
+//! `long_*` variants are used when user calls the program with
+//! `--help` and "short" variants are used with `-h` flag. In `structopt`,
+//! you can use them via [raw methods](#raw-methods), for example:
+//!
+//! ```
+//! # use structopt::StructOpt;
+//!
+//! #[derive(StructOpt)]
+//! #[structopt(about = "I am a program and I work, just pass `-h`")]
+//! struct Foo {
+//! #[structopt(short, help = "Pass `-h` and you'll see me!")]
+//! bar: String
+//! }
+//! ```
+//!
+//! For convenience, doc comments can be used instead of raw methods
+//! (this example works exactly like the one above):
+//!
+//! ```
+//! # use structopt::StructOpt;
+//!
+//! #[derive(StructOpt)]
+//! /// I am a program and I work, just pass `-h`
+//! struct Foo {
+//! /// Pass `-h` and you'll see me!
+//! bar: String
+//! }
+//! ```
+//!
+//! Doc comments on [top-level](#magical-methods) will be turned into
+//! `App::about/long_about` call (see below), doc comments on field-level are
+//! `Arg::help/long_help` calls.
+//!
+//! **Important:**
+//! _________________
+//!
+//! Raw methods have priority over doc comments!
+//!
+//! **Top level doc comments always generate `App::about/long_about` calls!**
+//! If you really want to use the `App::help/long_help` methods (you likely don't),
+//! use a raw method to override the `App::about` call generated from the doc comment.
+//! __________________
+//!
+//! ### `long_help` and `--help`
+//!
+//! A message passed to [`App::long_help`] or [`Arg::long_about`] will be displayed whenever
+//! your program is called with `--help` instead of `-h`. Of course, you can
+//! use them via raw methods as described [above](#help-messages).
+//!
+//! The more convenient way is to use a so-called "long" doc comment:
+//!
+//! ```
+//! # use structopt::StructOpt;
+//! #[derive(StructOpt)]
+//! /// Hi there, I'm Robo!
+//! ///
+//! /// I like beeping, stumbling, eating your electricity,
+//! /// and making records of you singing in a shower.
+//! /// Pay up, or I'll upload it to youtube!
+//! struct Robo {
+//! /// Call my brother SkyNet.
+//! ///
+//! /// I am artificial superintelligence. I won't rest
+//! /// until I'll have destroyed humanity. Enjoy your
+//! /// pathetic existence, you mere mortals.
+//! #[structopt(long)]
+//! kill_all_humans: bool
+//! }
+//! ```
+//!
+//! A long doc comment consists of three parts:
+//! * Short summary
+//! * A blank line (whitespace only)
+//! * Detailed description, all the rest
+//!
+//! In other words, "long" doc comment consists of two or more paragraphs,
+//! with the first being a summary and the rest being the detailed description.
+//!
+//! **A long comment will result in two method calls**, `help(<summary>)` and
+//! `long_help(<whole comment>)`, so clap will display the summary with `-h`
+//! and the whole help message on `--help` (see below).
+//!
+//! So, the example above will be turned into this (details omitted):
+//! ```
+//! clap::App::new("<name>")
+//! .about("Hi there, I'm Robo!")
+//! .long_about("Hi there, I'm Robo!\n\n\
+//! I like beeping, stumbling, eating your electricity,\
+//! and making records of you singing in a shower.\
+//! Pay up or I'll upload it to youtube!")
+//! // args...
+//! # ;
+//! ```
+//!
+//! ### `-h` vs `--help` (A.K.A `help()` vs `long_help()`)
+//!
+//! The `-h` flag is not the same as `--help`.
+//!
+//! -h corresponds to Arg::help/App::about and requests short "summary" messages
+//! while --help corresponds to Arg::long_help/App::long_about and requests more
+//! detailed, descriptive messages.
+//!
+//! It is entirely up to `clap` what happens if you used only one of
+//! [`Arg::help`]/[`Arg::long_help`], see `clap`'s documentation for these methods.
+//!
+//! As of clap v2.33, if only a short message ([`Arg::help`]) or only
+//! a long ([`Arg::long_help`]) message is provided, clap will use it
+//! for both -h and --help. The same logic applies to `about/long_about`.
+//!
+//! ### Doc comment preprocessing and `#[structopt(verbatim_doc_comment)]`
+//!
+//! `structopt` applies some preprocessing to doc comments to ease the most common uses:
+//!
+//! * Strip leading and trailing whitespace from every line, if present.
+//!
+//! * Strip leading and trailing blank lines, if present.
+//!
+//! * Interpret each group of non-empty lines as a word-wrapped paragraph.
+//!
+//! We replace newlines within paragraphs with spaces to allow the output
+//! to be re-wrapped to the terminal width.
+//!
+//! * Strip any excess blank lines so that there is exactly one per paragraph break.
+//!
+//! * If the first paragraph ends in exactly one period,
+//! remove the trailing period (i.e. strip trailing periods but not trailing ellipses).
+//!
+//! Sometimes you don't want this preprocessing to apply, for example the comment contains
+//! some ASCII art or markdown tables, you would need to preserve LFs along with
+//! blank lines and the leading/trailing whitespace. You can ask `structopt` to preserve them
+//! via `#[structopt(verbatim_doc_comment)]` attribute.
+//!
+//! **This attribute must be applied to each field separately**, there's no global switch.
+//!
+//! **Important:**
+//! ______________
+//! Keep in mind that `structopt` will *still* remove one leading space from each
+//! line, even if this attribute is present, to allow for a space between
+//! `///` and the content.
+//!
+//! Also, `structopt` will *still* remove leading and trailing blank lines so
+//! these formats are equivalent:
+//!
+//! ```ignore
+//! /** This is a doc comment
+//!
+//! Hello! */
+//!
+//! /**
+//! This is a doc comment
+//!
+//! Hello!
+//! */
+//!
+//! /// This is a doc comment
+//! ///
+//! /// Hello!
+//! ```
+//!
+//! Summary
+//! ______________
+//!
+//! [`App::about`]: https://docs.rs/clap/2/clap/struct.App.html#method.about
+//! [`App::long_about`]: https://docs.rs/clap/2/clap/struct.App.html#method.long_about
+//! [`Arg::help`]: https://docs.rs/clap/2/clap/struct.Arg.html#method.help
+//! [`Arg::long_help`]: https://docs.rs/clap/2/clap/struct.Arg.html#method.long_help
+//!
+//! ## Environment variable fallback
+//!
+//! It is possible to specify an environment variable fallback option for an arguments
+//! so that its value is taken from the specified environment variable if not
+//! given through the command-line:
+//!
+//! ```
+//! # use structopt::StructOpt;
+//!
+//! #[derive(StructOpt)]
+//! struct Foo {
+//! #[structopt(short, long, env = "PARAMETER_VALUE")]
+//! parameter_value: String
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! By default, values from the environment are shown in the help output (i.e. when invoking
+//! `--help`):
+//!
+//! ```shell
+//! $ cargo run -- --help
+//! ...
+//! OPTIONS:
+//! -p, --parameter-value <parameter-value> [env: PARAMETER_VALUE=env_value]
+//! ```
+//!
+//! In some cases this may be undesirable, for example when being used for passing
+//! credentials or secret tokens. In those cases you can use `hide_env_values` to avoid
+//! having structopt emit the actual secret values:
+//! ```
+//! # use structopt::StructOpt;
+//!
+//! #[derive(StructOpt)]
+//! struct Foo {
+//! #[structopt(long = "secret", env = "SECRET_VALUE", hide_env_values = true)]
+//! secret_value: String
+//! }
+//! ```
+//!
+//! ### Auto-deriving environment variables
+//!
+//! Environment variables tend to be called after the corresponding `struct`'s field,
+//! as in example above. The field is `secret_value` and the env var is "SECRET_VALUE";
+//! the name is the same, except casing is different.
+//!
+//! It's pretty tedious and error-prone to type the same name twice,
+//! so you can ask `structopt` to do that for you.
+//!
+//! ```
+//! # use structopt::StructOpt;
+//!
+//! #[derive(StructOpt)]
+//! struct Foo {
+//! #[structopt(long = "secret", env)]
+//! secret_value: String
+//! }
+//! ```
+//!
+//! It works just like `#[structopt(short/long)]`: if `env` is not set to some concrete
+//! value the value will be derived from the field's name. This is controlled by
+//! `#[structopt(rename_all_env)]`.
+//!
+//! `rename_all_env` works exactly as `rename_all` (including overriding)
+//! except default casing is `SCREAMING_SNAKE_CASE` instead of `kebab-case`.
+//!
+//! ## Skipping fields
+//!
+//! Sometimes you may want to add a field to your `Opt` struct that is not
+//! a command line option and `clap` should know nothing about it. You can ask
+//! `structopt` to skip the field entirely via `#[structopt(skip = value)]`
+//! (`value` must implement `Into<FieldType>`)
+//! or `#[structopt(skip)]` if you want assign the field with `Default::default()`
+//! (obviously, the field's type must implement `Default`).
+//!
+//! ```
+//! # use structopt::StructOpt;
+//! #[derive(StructOpt)]
+//! pub struct Opt {
+//! #[structopt(long, short)]
+//! number: u32,
+//!
+//! // these fields are to be assigned with Default::default()
+//!
+//! #[structopt(skip)]
+//! k: String,
+//! #[structopt(skip)]
+//! v: Vec<u32>,
+//!
+//! // these fields get set explicitly
+//!
+//! #[structopt(skip = vec![1, 2, 3])]
+//! k2: Vec<u32>,
+//! #[structopt(skip = "cake")] // &str implements Into<String>
+//! v2: String,
+//! }
+//! ```
+//!
+//! ## Subcommands
+//!
+//! Some applications, especially large ones, split their functionality
+//! through the use of "subcommands". Each of these act somewhat like a separate
+//! command, but is part of the larger group.
+//! One example is `git`, which has subcommands such as `add`, `commit`,
+//! and `clone`, to mention just a few.
+//!
+//! `clap` has this functionality, and `structopt` supports it through enums:
+//!
+//! ```
+//! # use structopt::StructOpt;
+//!
+//! # use std::path::PathBuf;
+//! #[derive(StructOpt)]
+//! #[structopt(about = "the stupid content tracker")]
+//! enum Git {
+//! Add {
+//! #[structopt(short)]
+//! interactive: bool,
+//! #[structopt(short)]
+//! patch: bool,
+//! #[structopt(parse(from_os_str))]
+//! files: Vec<PathBuf>
+//! },
+//! Fetch {
+//! #[structopt(long)]
+//! dry_run: bool,
+//! #[structopt(long)]
+//! all: bool,
+//! repository: Option<String>
+//! },
+//! Commit {
+//! #[structopt(short)]
+//! message: Option<String>,
+//! #[structopt(short)]
+//! all: bool
+//! }
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! Using `derive(StructOpt)` on an enum instead of a struct will produce
+//! a `clap::App` that only takes subcommands. So `git add`, `git fetch`,
+//! and `git commit` would be commands allowed for the above example.
+//!
+//! `structopt` also provides support for applications where certain flags
+//! need to apply to all subcommands, as well as nested subcommands:
+//!
+//! ```
+//! # use structopt::StructOpt;
+//! # fn main() {}
+//! #[derive(StructOpt)]
+//! struct MakeCookie {
+//! #[structopt(name = "supervisor", default_value = "Puck", long = "supervisor")]
+//! supervising_faerie: String,
+//! /// The faerie tree this cookie is being made in.
+//! tree: Option<String>,
+//! #[structopt(subcommand)] // Note that we mark a field as a subcommand
+//! cmd: Command
+//! }
+//!
+//! #[derive(StructOpt)]
+//! enum Command {
+//! /// Pound acorns into flour for cookie dough.
+//! Pound {
+//! acorns: u32
+//! },
+//! /// Add magical sparkles -- the secret ingredient!
+//! Sparkle {
+//! #[structopt(short, parse(from_occurrences))]
+//! magicality: u64,
+//! #[structopt(short)]
+//! color: String
+//! },
+//! Finish(Finish),
+//! }
+//!
+//! // Subcommand can also be externalized by using a 1-uple enum variant
+//! #[derive(StructOpt)]
+//! struct Finish {
+//! #[structopt(short)]
+//! time: u32,
+//! #[structopt(subcommand)] // Note that we mark a field as a subcommand
+//! finish_type: FinishType
+//! }
+//!
+//! // subsubcommand!
+//! #[derive(StructOpt)]
+//! enum FinishType {
+//! Glaze {
+//! applications: u32
+//! },
+//! Powder {
+//! flavor: String,
+//! dips: u32
+//! }
+//! }
+//! ```
+//!
+//! Marking a field with `structopt(subcommand)` will add the subcommands of the
+//! designated enum to the current `clap::App`. The designated enum *must* also
+//! be derived `StructOpt`. So the above example would take the following
+//! commands:
+//!
+//! + `make-cookie pound 50`
+//! + `make-cookie sparkle -mmm --color "green"`
+//! + `make-cookie finish 130 glaze 3`
+//!
+//! ### Optional subcommands
+//!
+//! Subcommands may be optional:
+//!
+//! ```
+//! # use structopt::StructOpt;
+//! # fn main() {}
+//! #[derive(StructOpt)]
+//! struct Foo {
+//! file: String,
+//! #[structopt(subcommand)]
+//! cmd: Option<Command>
+//! }
+//!
+//! #[derive(StructOpt)]
+//! enum Command {
+//! Bar,
+//! Baz,
+//! Quux
+//! }
+//! ```
+//!
+//! ## Flattening
+//!
+//! It can sometimes be useful to group related arguments in a substruct,
+//! while keeping the command-line interface flat. In these cases you can mark
+//! a field as `flatten` and give it another type that derives `StructOpt`:
+//!
+//! ```
+//! # use structopt::StructOpt;
+//! # fn main() {}
+//! #[derive(StructOpt)]
+//! struct Cmdline {
+//! /// switch on verbosity
+//! #[structopt(short)]
+//! verbose: bool,
+//! #[structopt(flatten)]
+//! daemon_opts: DaemonOpts,
+//! }
+//!
+//! #[derive(StructOpt)]
+//! struct DaemonOpts {
+//! /// daemon user
+//! #[structopt(short)]
+//! user: String,
+//! /// daemon group
+//! #[structopt(short)]
+//! group: String,
+//! }
+//! ```
+//!
+//! In this example, the derived `Cmdline` parser will support the options `-v`,
+//! `-u` and `-g`.
+//!
+//! This feature also makes it possible to define a `StructOpt` struct in a
+//! library, parse the corresponding arguments in the main argument parser, and
+//! pass off this struct to a handler provided by that library.
+//!
+//! ## Custom string parsers
+//!
+//! If the field type does not have a `FromStr` implementation, or you would
+//! like to provide a custom parsing scheme other than `FromStr`, you may
+//! provide a custom string parser using `parse(...)` like this:
+//!
+//! ```
+//! # use structopt::StructOpt;
+//! # fn main() {}
+//! use std::num::ParseIntError;
+//! use std::path::PathBuf;
+//!
+//! fn parse_hex(src: &str) -> Result<u32, ParseIntError> {
+//! u32::from_str_radix(src, 16)
+//! }
+//!
+//! #[derive(StructOpt)]
+//! struct HexReader {
+//! #[structopt(short, parse(try_from_str = parse_hex))]
+//! number: u32,
+//! #[structopt(short, parse(from_os_str))]
+//! output: PathBuf,
+//! }
+//! ```
+//!
+//! There are five kinds of custom parsers:
+//!
+//! | Kind | Signature | Default |
+//! |-------------------|---------------------------------------|---------------------------------|
+//! | `from_str` | `fn(&str) -> T` | `::std::convert::From::from` |
+//! | `try_from_str` | `fn(&str) -> Result<T, E>` | `::std::str::FromStr::from_str` |
+//! | `from_os_str` | `fn(&OsStr) -> T` | `::std::convert::From::from` |
+//! | `try_from_os_str` | `fn(&OsStr) -> Result<T, OsString>` | (no default function) |
+//! | `from_occurrences`| `fn(u64) -> T` | `value as T` |
+//! | `from_flag` | `fn(bool) -> T` | `::std::convert::From::from` |
+//!
+//! The `from_occurrences` parser is special. Using `parse(from_occurrences)`
+//! results in the _number of flags occurrences_ being stored in the relevant
+//! field or being passed to the supplied function. In other words, it converts
+//! something like `-vvv` to `3`. This is equivalent to
+//! `.takes_value(false).multiple(true)`. Note that the default parser can only
+//! be used with fields of integer types (`u8`, `usize`, `i64`, etc.).
+//!
+//! The `from_flag` parser is also special. Using `parse(from_flag)` or
+//! `parse(from_flag = some_func)` will result in the field being treated as a
+//! flag even if it does not have type `bool`.
+//!
+//! When supplying a custom string parser, `bool` will not be treated specially:
+//!
+//! Type | Effect | Added method call to `clap::Arg`
+//! ------------|-------------------|--------------------------------------
+//! `Option<T>` | optional argument | `.takes_value(true).multiple(false)`
+//! `Vec<T>` | list of arguments | `.takes_value(true).multiple(true)`
+//! `T` | required argument | `.takes_value(true).multiple(false).required(!has_default)`
+//!
+//! In the `try_from_*` variants, the function will run twice on valid input:
+//! once to validate, and once to parse. Hence, make sure the function is
+//! side-effect-free.
+
+#[doc(hidden)]
+pub use structopt_derive::*;
+
+use std::ffi::OsString;
+
+/// Re-export of clap
+pub use clap;
+
+/// A struct that is converted from command line arguments.
+pub trait StructOpt {
+ /// Returns the corresponding `clap::App`.
+ fn clap<'a, 'b>() -> clap::App<'a, 'b>;
+
+ /// Creates the struct from `clap::ArgMatches`. It cannot fail
+ /// with a parameter generated by `clap` by construction.
+ fn from_clap(matches: &clap::ArgMatches<'_>) -> Self;
+
+ /// Gets the struct from the command line arguments. Print the
+ /// error message and quit the program in case of failure.
+ fn from_args() -> Self
+ where
+ Self: Sized,
+ {
+ Self::from_clap(&Self::clap().get_matches())
+ }
+
+ /// Gets the struct from any iterator such as a `Vec` of your making.
+ /// Print the error message and quit the program in case of failure.
+ fn from_iter<I>(iter: I) -> Self
+ where
+ Self: Sized,
+ I: IntoIterator,
+ I::Item: Into<OsString> + Clone,
+ {
+ Self::from_clap(&Self::clap().get_matches_from(iter))
+ }
+
+ /// Gets the struct from any iterator such as a `Vec` of your making.
+ ///
+ /// Returns a `clap::Error` in case of failure. This does *not* exit in the
+ /// case of `--help` or `--version`, to achieve the same behavior as
+ /// `from_iter()` you must call `.exit()` on the error value.
+ fn from_iter_safe<I>(iter: I) -> Result<Self, clap::Error>
+ where
+ Self: Sized,
+ I: IntoIterator,
+ I::Item: Into<OsString> + Clone,
+ {
+ Ok(Self::from_clap(&Self::clap().get_matches_from_safe(iter)?))
+ }
+}
+
+/// This trait is NOT API. **SUBJECT TO CHANGE WITHOUT NOTICE!**.
+#[doc(hidden)]
+pub trait StructOptInternal: StructOpt {
+ fn augment_clap<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
+ app
+ }
+
+ fn is_subcommand() -> bool {
+ false
+ }
+
+ fn from_subcommand<'a, 'b>(_sub: (&'b str, Option<&'b clap::ArgMatches<'a>>)) -> Option<Self>
+ where
+ Self: std::marker::Sized,
+ {
+ None
+ }
+}
+
+impl<T: StructOpt> StructOpt for Box<T> {
+ fn clap<'a, 'b>() -> clap::App<'a, 'b> {
+ <T as StructOpt>::clap()
+ }
+
+ fn from_clap(matches: &clap::ArgMatches<'_>) -> Self {
+ Box::new(<T as StructOpt>::from_clap(matches))
+ }
+}
+
+impl<T: StructOptInternal> StructOptInternal for Box<T> {
+ #[doc(hidden)]
+ fn is_subcommand() -> bool {
+ <T as StructOptInternal>::is_subcommand()
+ }
+
+ #[doc(hidden)]
+ fn from_subcommand<'a, 'b>(sub: (&'b str, Option<&'b clap::ArgMatches<'a>>)) -> Option<Self> {
+ <T as StructOptInternal>::from_subcommand(sub).map(Box::new)
+ }
+
+ #[doc(hidden)]
+ fn augment_clap<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
+ <T as StructOptInternal>::augment_clap(app)
+ }
+}
diff --git a/structopt/structopt-derive/Cargo.toml b/structopt/structopt-derive/Cargo.toml
new file mode 100644
index 0000000..ad547af
--- /dev/null
+++ b/structopt/structopt-derive/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+name = "structopt-derive"
+version = "0.4.0"
+edition = "2018"
+authors = ["Guillaume Pinot <texitoi@texitoi.eu>"]
+description = "Parse command line argument by defining a struct, derive crate."
+documentation = "https://docs.rs/structopt-derive"
+repository = "https://github.com/TeXitoi/structopt"
+keywords = ["clap", "cli", "derive", "docopt"]
+categories = ["command-line-interface"]
+license = "Apache-2.0/MIT"
+
+[badges]
+travis-ci = { repository = "TeXitoi/structopt" }
+
+[dependencies]
+syn = { version = "1", features = ["full"] }
+quote = "1"
+proc-macro2 = "1"
+heck = "0.3.0"
+proc-macro-error = "0.4.3"
+
+[features]
+paw = []
+
+[lib]
+proc-macro = true
diff --git a/structopt/structopt-derive/LICENSE-APACHE b/structopt/structopt-derive/LICENSE-APACHE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/structopt/structopt-derive/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/structopt/structopt-derive/LICENSE-MIT b/structopt/structopt-derive/LICENSE-MIT
new file mode 100644
index 0000000..e931b83
--- /dev/null
+++ b/structopt/structopt-derive/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+
+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/structopt/structopt-derive/src/attrs.rs b/structopt/structopt-derive/src/attrs.rs
new file mode 100644
index 0000000..ce684a2
--- /dev/null
+++ b/structopt/structopt-derive/src/attrs.rs
@@ -0,0 +1,620 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::doc_comments::process_doc_comment;
+use crate::{parse::*, spanned::Sp, ty::Ty};
+
+use std::env;
+
+use heck::{CamelCase, KebabCase, MixedCase, ShoutySnakeCase, SnakeCase};
+use proc_macro2::{Span, TokenStream};
+use proc_macro_error::abort;
+use quote::{quote, quote_spanned, ToTokens};
+use syn::{self, ext::IdentExt, spanned::Spanned, Attribute, Expr, Ident, LitStr, MetaNameValue};
+
+#[derive(Clone)]
+pub enum Kind {
+ Arg(Sp<Ty>),
+ Subcommand(Sp<Ty>),
+ FlattenStruct,
+ Skip(Option<Expr>),
+}
+
+#[derive(Clone)]
+pub struct Method {
+ name: Ident,
+ args: TokenStream,
+}
+
+#[derive(Clone)]
+pub struct Parser {
+ pub kind: Sp<ParserKind>,
+ pub func: TokenStream,
+}
+
+#[derive(Debug, PartialEq, Clone)]
+pub enum ParserKind {
+ FromStr,
+ TryFromStr,
+ FromOsStr,
+ TryFromOsStr,
+ FromOccurrences,
+ FromFlag,
+}
+
+/// Defines the casing for the attributes long representation.
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum CasingStyle {
+ /// Indicate word boundaries with uppercase letter, excluding the first word.
+ Camel,
+ /// Keep all letters lowercase and indicate word boundaries with hyphens.
+ Kebab,
+ /// Indicate word boundaries with uppercase letter, including the first word.
+ Pascal,
+ /// Keep all letters uppercase and indicate word boundaries with underscores.
+ ScreamingSnake,
+ /// Keep all letters lowercase and indicate word boundaries with underscores.
+ Snake,
+ /// Use the original attribute name defined in the code.
+ Verbatim,
+}
+
+#[derive(Clone)]
+pub enum Name {
+ Derived(Ident),
+ Assigned(LitStr),
+}
+
+#[derive(Clone)]
+pub struct Attrs {
+ name: Name,
+ casing: Sp<CasingStyle>,
+ env_casing: Sp<CasingStyle>,
+ doc_comment: Vec<Method>,
+ methods: Vec<Method>,
+ parser: Sp<Parser>,
+ author: Option<Method>,
+ about: Option<Method>,
+ version: Option<Method>,
+ no_version: Option<Ident>,
+ verbatim_doc_comment: Option<Ident>,
+ has_custom_parser: bool,
+ kind: Sp<Kind>,
+}
+
+impl Method {
+ pub fn new(name: Ident, args: TokenStream) -> Self {
+ Method { name, args }
+ }
+
+ fn from_lit_or_env(ident: Ident, lit: Option<LitStr>, env_var: &str) -> Option<Self> {
+ let mut lit = match lit {
+ Some(lit) => lit,
+
+ None => match env::var(env_var) {
+ Ok(val) => LitStr::new(&val, ident.span()),
+ Err(_) => {
+ abort!(ident.span(),
+ "cannot derive `{}` from Cargo.toml", ident;
+ note = "`{}` environment variable is not set", env_var;
+ help = "use `{} = \"...\"` to set {} manually", ident, ident;
+ );
+ }
+ },
+ };
+
+ if ident == "author" {
+ let edited = process_author_str(&lit.value());
+ lit = LitStr::new(&edited, lit.span());
+ }
+
+ Some(Method::new(ident, quote!(#lit)))
+ }
+}
+
+impl ToTokens for Method {
+ fn to_tokens(&self, ts: &mut TokenStream) {
+ let Method { ref name, ref args } = self;
+ quote!(.#name(#args)).to_tokens(ts);
+ }
+}
+
+impl Parser {
+ fn default_spanned(span: Span) -> Sp<Self> {
+ let kind = Sp::new(ParserKind::TryFromStr, span);
+ let func = quote_spanned!(span=> ::std::str::FromStr::from_str);
+ Sp::new(Parser { kind, func }, span)
+ }
+
+ fn from_spec(parse_ident: Ident, spec: ParserSpec) -> Sp<Self> {
+ use ParserKind::*;
+
+ let kind = match &*spec.kind.to_string() {
+ "from_str" => FromStr,
+ "try_from_str" => TryFromStr,
+ "from_os_str" => FromOsStr,
+ "try_from_os_str" => TryFromOsStr,
+ "from_occurrences" => FromOccurrences,
+ "from_flag" => FromFlag,
+ s => abort!(spec.kind.span(), "unsupported parser `{}`", s),
+ };
+
+ let func = match spec.parse_func {
+ None => match kind {
+ FromStr | FromOsStr => {
+ quote_spanned!(spec.kind.span()=> ::std::convert::From::from)
+ }
+ TryFromStr => quote_spanned!(spec.kind.span()=> ::std::str::FromStr::from_str),
+ TryFromOsStr => abort!(
+ spec.kind.span(),
+ "you must set parser for `try_from_os_str` explicitly"
+ ),
+ FromOccurrences => quote_spanned!(spec.kind.span()=> { |v| v as _ }),
+ FromFlag => quote_spanned!(spec.kind.span()=> ::std::convert::From::from),
+ },
+
+ Some(func) => match func {
+ syn::Expr::Path(_) => quote!(#func),
+ _ => abort!(func.span(), "`parse` argument must be a function path"),
+ },
+ };
+
+ let kind = Sp::new(kind, spec.kind.span());
+ let parser = Parser { kind, func };
+ Sp::new(parser, parse_ident.span())
+ }
+}
+
+impl CasingStyle {
+ fn from_lit(name: LitStr) -> Sp<Self> {
+ use CasingStyle::*;
+
+ let normalized = name.value().to_camel_case().to_lowercase();
+ let cs = |kind| Sp::new(kind, name.span());
+
+ match normalized.as_ref() {
+ "camel" | "camelcase" => cs(Camel),
+ "kebab" | "kebabcase" => cs(Kebab),
+ "pascal" | "pascalcase" => cs(Pascal),
+ "screamingsnake" | "screamingsnakecase" => cs(ScreamingSnake),
+ "snake" | "snakecase" => cs(Snake),
+ "verbatim" | "verbatimcase" => cs(Verbatim),
+ s => abort!(name.span(), "unsupported casing: `{}`", s),
+ }
+ }
+}
+
+impl Name {
+ pub fn translate(self, style: CasingStyle) -> LitStr {
+ use CasingStyle::*;
+
+ match self {
+ Name::Assigned(lit) => lit,
+ Name::Derived(ident) => {
+ let s = ident.unraw().to_string();
+ let s = match style {
+ Pascal => s.to_camel_case(),
+ Kebab => s.to_kebab_case(),
+ Camel => s.to_mixed_case(),
+ ScreamingSnake => s.to_shouty_snake_case(),
+ Snake => s.to_snake_case(),
+ Verbatim => s,
+ };
+ LitStr::new(&s, ident.span())
+ }
+ }
+ }
+}
+
+impl Attrs {
+ fn new(
+ default_span: Span,
+ name: Name,
+ casing: Sp<CasingStyle>,
+ env_casing: Sp<CasingStyle>,
+ ) -> Self {
+ Self {
+ name,
+ casing,
+ env_casing,
+ doc_comment: vec![],
+ methods: vec![],
+ parser: Parser::default_spanned(default_span),
+ about: None,
+ author: None,
+ version: None,
+ no_version: None,
+ verbatim_doc_comment: None,
+
+ has_custom_parser: false,
+ kind: Sp::new(Kind::Arg(Sp::new(Ty::Other, default_span)), default_span),
+ }
+ }
+
+ /// push `.method("str literal")`
+ fn push_str_method(&mut self, name: Sp<String>, arg: Sp<String>) {
+ if *name == "name" {
+ self.name = Name::Assigned(arg.as_lit());
+ } else {
+ self.methods
+ .push(Method::new(name.as_ident(), quote!(#arg)))
+ }
+ }
+
+ fn push_attrs(&mut self, attrs: &[Attribute]) {
+ use crate::parse::StructOptAttr::*;
+
+ for attr in parse_structopt_attributes(attrs) {
+ match attr {
+ Short(ident) | Long(ident) => {
+ self.push_str_method(
+ ident.into(),
+ self.name.clone().translate(*self.casing).into(),
+ );
+ }
+
+ Env(ident) => {
+ self.push_str_method(
+ ident.into(),
+ self.name.clone().translate(*self.env_casing).into(),
+ );
+ }
+
+ Subcommand(ident) => {
+ let ty = Sp::call_site(Ty::Other);
+ let kind = Sp::new(Kind::Subcommand(ty), ident.span());
+ self.set_kind(kind);
+ }
+
+ Flatten(ident) => {
+ let kind = Sp::new(Kind::FlattenStruct, ident.span());
+ self.set_kind(kind);
+ }
+
+ Skip(ident, expr) => {
+ let kind = Sp::new(Kind::Skip(expr), ident.span());
+ self.set_kind(kind);
+ }
+
+ NoVersion(ident) => self.no_version = Some(ident),
+
+ VerbatimDocComment(ident) => self.verbatim_doc_comment = Some(ident),
+
+ About(ident, about) => {
+ self.about = Method::from_lit_or_env(ident, about, "CARGO_PKG_DESCRIPTION");
+ }
+
+ Author(ident, author) => {
+ self.author = Method::from_lit_or_env(ident, author, "CARGO_PKG_AUTHORS");
+ }
+
+ Version(ident, version) => {
+ self.version = Some(Method::new(ident, quote!(#version)))
+ }
+
+ NameLitStr(name, lit) => {
+ self.push_str_method(name.into(), lit.into());
+ }
+
+ NameExpr(name, expr) => self.methods.push(Method::new(name, quote!(#expr))),
+
+ MethodCall(name, args) => self.methods.push(Method::new(name, quote!(#(#args),*))),
+
+ RenameAll(_, casing_lit) => {
+ self.casing = CasingStyle::from_lit(casing_lit);
+ }
+
+ RenameAllEnv(_, casing_lit) => {
+ self.env_casing = CasingStyle::from_lit(casing_lit);
+ }
+
+ Parse(ident, spec) => {
+ self.has_custom_parser = true;
+ self.parser = Parser::from_spec(ident, spec);
+ }
+ }
+ }
+ }
+
+ fn push_doc_comment(&mut self, attrs: &[Attribute], name: &str) {
+ use crate::Lit::*;
+ use crate::Meta::*;
+
+ let comment_parts: Vec<_> = attrs
+ .iter()
+ .filter(|attr| attr.path.is_ident("doc"))
+ .filter_map(|attr| {
+ if let Ok(NameValue(MetaNameValue { lit: Str(s), .. })) = attr.parse_meta() {
+ Some(s.value())
+ } else {
+ // non #[doc = "..."] attributes are not our concern
+ // we leave them for rustc to handle
+ None
+ }
+ })
+ .collect();
+
+ self.doc_comment =
+ process_doc_comment(comment_parts, name, self.verbatim_doc_comment.is_none());
+ }
+
+ pub fn from_struct(
+ span: Span,
+ attrs: &[Attribute],
+ name: Name,
+ argument_casing: Sp<CasingStyle>,
+ env_casing: Sp<CasingStyle>,
+ ) -> Self {
+ let mut res = Self::new(span, name, argument_casing, env_casing);
+ res.push_attrs(attrs);
+ res.push_doc_comment(attrs, "about");
+
+ if res.has_custom_parser {
+ abort!(
+ res.parser.span(),
+ "`parse` attribute is only allowed on fields"
+ );
+ }
+ match &*res.kind {
+ Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"),
+ Kind::FlattenStruct => abort!(res.kind.span(), "flatten is only allowed on fields"),
+ Kind::Skip(_) => abort!(res.kind.span(), "skip is only allowed on fields"),
+ Kind::Arg(_) => res,
+ }
+ }
+
+ pub fn from_field(
+ field: &syn::Field,
+ struct_casing: Sp<CasingStyle>,
+ env_casing: Sp<CasingStyle>,
+ ) -> Self {
+ let name = field.ident.clone().unwrap();
+ let mut res = Self::new(
+ field.span(),
+ Name::Derived(name.clone()),
+ struct_casing,
+ env_casing,
+ );
+ res.push_doc_comment(&field.attrs, "help");
+ res.push_attrs(&field.attrs);
+
+ match &*res.kind {
+ Kind::FlattenStruct => {
+ if res.has_custom_parser {
+ abort!(
+ res.parser.span(),
+ "parse attribute is not allowed for flattened entry"
+ );
+ }
+ if res.has_explicit_methods() || res.has_doc_methods() {
+ abort!(
+ res.kind.span(),
+ "methods and doc comments are not allowed for flattened entry"
+ );
+ }
+ }
+ Kind::Subcommand(_) => {
+ if res.has_custom_parser {
+ abort!(
+ res.parser.span(),
+ "parse attribute is not allowed for subcommand"
+ );
+ }
+ if res.has_explicit_methods() {
+ abort!(
+ res.kind.span(),
+ "methods in attributes are not allowed for subcommand"
+ );
+ }
+
+ let ty = Ty::from_syn_ty(&field.ty);
+ match *ty {
+ Ty::OptionOption => {
+ abort!(
+ ty.span(),
+ "Option<Option<T>> type is not allowed for subcommand"
+ );
+ }
+ Ty::OptionVec => {
+ abort!(
+ ty.span(),
+ "Option<Vec<T>> type is not allowed for subcommand"
+ );
+ }
+ _ => (),
+ }
+
+ res.kind = Sp::new(Kind::Subcommand(ty), res.kind.span());
+ }
+ Kind::Skip(_) => {
+ if res.has_explicit_methods() {
+ abort!(
+ res.kind.span(),
+ "methods are not allowed for skipped fields"
+ );
+ }
+ }
+ Kind::Arg(orig_ty) => {
+ let mut ty = Ty::from_syn_ty(&field.ty);
+ if res.has_custom_parser {
+ match *ty {
+ Ty::Option | Ty::Vec | Ty::OptionVec => (),
+ _ => ty = Sp::new(Ty::Other, ty.span()),
+ }
+ }
+
+ match *ty {
+ Ty::Bool => {
+ if res.is_positional() && !res.has_custom_parser {
+ abort!(ty.span(),
+ "`bool` cannot be used as positional parameter with default parser";
+ help = "if you want to create a flag add `long` or `short`";
+ help = "If you really want a boolean parameter \
+ add an explicit parser, for example `parse(try_from_str)`";
+ note = "see also https://github.com/TeXitoi/structopt/tree/master/examples/true_or_false.rs";
+ )
+ }
+ if let Some(m) = res.find_method("default_value") {
+ abort!(m.name.span(), "default_value is meaningless for bool")
+ }
+ if let Some(m) = res.find_method("required") {
+ abort!(m.name.span(), "required is meaningless for bool")
+ }
+ }
+ Ty::Option => {
+ if let Some(m) = res.find_method("default_value") {
+ abort!(m.name.span(), "default_value is meaningless for Option")
+ }
+ if let Some(m) = res.find_method("required") {
+ abort!(m.name.span(), "required is meaningless for Option")
+ }
+ }
+ Ty::OptionOption => {
+ if res.is_positional() {
+ abort!(
+ ty.span(),
+ "Option<Option<T>> type is meaningless for positional argument"
+ )
+ }
+ }
+ Ty::OptionVec => {
+ if res.is_positional() {
+ abort!(
+ ty.span(),
+ "Option<Vec<T>> type is meaningless for positional argument"
+ )
+ }
+ }
+
+ _ => (),
+ }
+ res.kind = Sp::new(Kind::Arg(ty), orig_ty.span());
+ }
+ }
+
+ res
+ }
+
+ fn set_kind(&mut self, kind: Sp<Kind>) {
+ if let Kind::Arg(_) = *self.kind {
+ self.kind = kind;
+ } else {
+ abort!(
+ kind.span(),
+ "subcommand, flatten and skip cannot be used together"
+ );
+ }
+ }
+
+ pub fn has_method(&self, name: &str) -> bool {
+ self.find_method(name).is_some()
+ }
+
+ pub fn find_method(&self, name: &str) -> Option<&Method> {
+ self.methods.iter().find(|m| m.name == name)
+ }
+
+ /// generate methods from attributes on top of struct or enum
+ pub fn top_level_methods(&self) -> TokenStream {
+ let version = match (&self.no_version, &self.version) {
+ (Some(no_version), Some(_)) => abort!(
+ no_version.span(),
+ "`no_version` and `version = \"version\"` can't be used together"
+ ),
+
+ (None, Some(m)) => m.to_token_stream(),
+
+ (None, None) => std::env::var("CARGO_PKG_VERSION")
+ .map(|version| quote!( .version(#version) ))
+ .unwrap_or_default(),
+
+ (Some(_), None) => quote!(),
+ };
+
+ let author = &self.author;
+ let about = &self.about;
+ let methods = &self.methods;
+ let doc_comment = &self.doc_comment;
+
+ quote!( #(#doc_comment)* #author #version #about #(#methods)* )
+ }
+
+ /// generate methods on top of a field
+ pub fn field_methods(&self) -> TokenStream {
+ let methods = &self.methods;
+ let doc_comment = &self.doc_comment;
+ quote!( #(#doc_comment)* #(#methods)* )
+ }
+
+ pub fn cased_name(&self) -> LitStr {
+ self.name.clone().translate(*self.casing)
+ }
+
+ pub fn parser(&self) -> &Sp<Parser> {
+ &self.parser
+ }
+
+ pub fn kind(&self) -> Sp<Kind> {
+ self.kind.clone()
+ }
+
+ pub fn casing(&self) -> Sp<CasingStyle> {
+ self.casing.clone()
+ }
+
+ pub fn env_casing(&self) -> Sp<CasingStyle> {
+ self.env_casing.clone()
+ }
+
+ pub fn is_positional(&self) -> bool {
+ self.methods
+ .iter()
+ .all(|m| m.name != "long" && m.name != "short")
+ }
+
+ pub fn has_explicit_methods(&self) -> bool {
+ self.methods
+ .iter()
+ .any(|m| m.name != "help" && m.name != "long_help")
+ }
+
+ pub fn has_doc_methods(&self) -> bool {
+ !self.doc_comment.is_empty()
+ || self.methods.iter().any(|m| {
+ m.name == "help"
+ || m.name == "long_help"
+ || m.name == "about"
+ || m.name == "long_about"
+ })
+ }
+}
+
+/// replace all `:` with `, ` when not inside the `<>`
+///
+/// `"author1:author2:author3" => "author1, author2, author3"`
+/// `"author1 <http://website1.com>:author2" => "author1 <http://website1.com>, author2"
+fn process_author_str(author: &str) -> String {
+ let mut res = String::with_capacity(author.len());
+ let mut inside_angle_braces = 0usize;
+
+ for ch in author.chars() {
+ if inside_angle_braces > 0 && ch == '>' {
+ inside_angle_braces -= 1;
+ res.push(ch);
+ } else if ch == '<' {
+ inside_angle_braces += 1;
+ res.push(ch);
+ } else if inside_angle_braces == 0 && ch == ':' {
+ res.push_str(", ");
+ } else {
+ res.push(ch);
+ }
+ }
+
+ res
+}
diff --git a/structopt/structopt-derive/src/doc_comments.rs b/structopt/structopt-derive/src/doc_comments.rs
new file mode 100644
index 0000000..06e1b14
--- /dev/null
+++ b/structopt/structopt-derive/src/doc_comments.rs
@@ -0,0 +1,103 @@
+//! The preprocessing we apply to doc comments.
+//!
+//! structopt works in terms of "paragraphs". Paragraph is a sequence of
+//! non-empty adjacent lines, delimited by sequences of blank (whitespace only) lines.
+
+use crate::attrs::Method;
+use quote::{format_ident, quote};
+use std::iter;
+
+pub fn process_doc_comment(lines: Vec<String>, name: &str, preprocess: bool) -> Vec<Method> {
+ // multiline comments (`/** ... */`) may have LFs (`\n`) in them,
+ // we need to split so we could handle the lines correctly
+ //
+ // we also need to remove leading and trailing blank lines
+ let mut lines: Vec<&str> = lines
+ .iter()
+ .skip_while(|s| is_blank(s))
+ .flat_map(|s| s.split('\n'))
+ .collect();
+
+ while let Some(true) = lines.last().map(|s| is_blank(s)) {
+ lines.pop();
+ }
+
+ // remove one leading space no matter what
+ for line in lines.iter_mut() {
+ if line.starts_with(' ') {
+ *line = &line[1..];
+ }
+ }
+
+ if lines.is_empty() {
+ return vec![];
+ }
+
+ let short_name = format_ident!("{}", name);
+ let long_name = format_ident!("long_{}", name);
+
+ if let Some(first_blank) = lines.iter().position(|s| is_blank(s)) {
+ let (short, long) = if preprocess {
+ let paragraphs = split_paragraphs(&lines);
+ let short = paragraphs[0].clone();
+ let long = paragraphs.join("\n\n");
+ (remove_period(short), long)
+ } else {
+ let short = lines[..first_blank].join("\n");
+ let long = lines.join("\n");
+ (short, long)
+ };
+
+ vec![
+ Method::new(short_name, quote!(#short)),
+ Method::new(long_name, quote!(#long)),
+ ]
+ } else {
+ let short = if preprocess {
+ let s = merge_lines(&lines);
+ remove_period(s)
+ } else {
+ lines.join("\n")
+ };
+
+ vec![Method::new(short_name, quote!(#short))]
+ }
+}
+
+fn split_paragraphs(lines: &[&str]) -> Vec<String> {
+ let mut last_line = 0;
+ iter::from_fn(|| {
+ let slice = &lines[last_line..];
+ let start = slice.iter().position(|s| !is_blank(s)).unwrap_or(0);
+
+ let slice = &slice[start..];
+ let len = slice
+ .iter()
+ .position(|s| is_blank(s))
+ .unwrap_or(slice.len());
+
+ last_line += start + len;
+
+ if len != 0 {
+ Some(merge_lines(&slice[..len]))
+ } else {
+ None
+ }
+ })
+ .collect()
+}
+
+fn remove_period(mut s: String) -> String {
+ if s.ends_with('.') && !s.ends_with("..") {
+ s.pop();
+ }
+ s
+}
+
+fn is_blank(s: &str) -> bool {
+ s.trim().is_empty()
+}
+
+fn merge_lines(lines: &[&str]) -> String {
+ lines.iter().map(|s| s.trim()).collect::<Vec<_>>().join(" ")
+}
diff --git a/structopt/structopt-derive/src/lib.rs b/structopt/structopt-derive/src/lib.rs
new file mode 100644
index 0000000..87eaf1f
--- /dev/null
+++ b/structopt/structopt-derive/src/lib.rs
@@ -0,0 +1,667 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This crate is custom derive for `StructOpt`. It should not be used
+//! directly. See [structopt documentation](https://docs.rs/structopt)
+//! for the usage of `#[derive(StructOpt)]`.
+
+#![allow(clippy::large_enum_variant)]
+
+extern crate proc_macro;
+
+mod attrs;
+mod doc_comments;
+mod parse;
+mod spanned;
+mod ty;
+
+use crate::{
+ attrs::{Attrs, CasingStyle, Kind, Name, ParserKind},
+ spanned::Sp,
+ ty::{sub_type, Ty},
+};
+
+use proc_macro2::{Span, TokenStream};
+use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy};
+use quote::{quote, quote_spanned};
+use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *};
+
+/// Default casing style for generated arguments.
+const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
+
+/// Default casing style for environment variables
+const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
+
+/// Output for the `gen_xxx()` methods were we need more than a simple stream of tokens.
+///
+/// The output of a generation method is not only the stream of new tokens but also the attribute
+/// information of the current element. These attribute information may contain valuable information
+/// for any kind of child arguments.
+struct GenOutput {
+ tokens: TokenStream,
+ attrs: Attrs,
+}
+
+/// Generates the `StructOpt` impl.
+#[proc_macro_derive(StructOpt, attributes(structopt))]
+#[proc_macro_error]
+pub fn structopt(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ let input: DeriveInput = syn::parse(input).unwrap();
+ let gen = impl_structopt(&input);
+ gen.into()
+}
+
+/// Generate a block of code to add arguments/subcommands corresponding to
+/// the `fields` to an app.
+fn gen_augmentation(
+ fields: &Punctuated<Field, Comma>,
+ app_var: &Ident,
+ parent_attribute: &Attrs,
+) -> TokenStream {
+ let mut subcmds = fields.iter().filter_map(|field| {
+ let attrs = Attrs::from_field(
+ field,
+ parent_attribute.casing(),
+ parent_attribute.env_casing(),
+ );
+ let kind = attrs.kind();
+ if let Kind::Subcommand(ty) = &*kind {
+ let subcmd_type = match (**ty, sub_type(&field.ty)) {
+ (Ty::Option, Some(sub_type)) => sub_type,
+ _ => &field.ty,
+ };
+ let required = if **ty == Ty::Option {
+ quote!()
+ } else {
+ quote_spanned! { kind.span()=>
+ let #app_var = #app_var.setting(
+ ::structopt::clap::AppSettings::SubcommandRequiredElseHelp
+ );
+ }
+ };
+
+ let span = field.span();
+ let ts = quote! {
+ let #app_var = <#subcmd_type as ::structopt::StructOptInternal>::augment_clap(
+ #app_var
+ );
+ #required
+ };
+ Some((span, ts))
+ } else {
+ None
+ }
+ });
+
+ let subcmd = subcmds.next().map(|(_, ts)| ts);
+ if let Some((span, _)) = subcmds.next() {
+ abort!(
+ span,
+ "multiple subcommand sets are not allowed, that's the second"
+ );
+ }
+
+ let args = fields.iter().filter_map(|field| {
+ let attrs = Attrs::from_field(
+ field,
+ parent_attribute.casing(),
+ parent_attribute.env_casing(),
+ );
+ let kind = attrs.kind();
+ match &*kind {
+ Kind::Subcommand(_) | Kind::Skip(_) => None,
+ Kind::FlattenStruct => {
+ let ty = &field.ty;
+ Some(quote_spanned! { kind.span()=>
+ let #app_var = <#ty as ::structopt::StructOptInternal>::augment_clap(#app_var);
+ let #app_var = if <#ty as ::structopt::StructOptInternal>::is_subcommand() {
+ #app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp)
+ } else {
+ #app_var
+ };
+ })
+ }
+ Kind::Arg(ty) => {
+ let convert_type = match **ty {
+ Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
+ Ty::OptionOption | Ty::OptionVec => {
+ sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
+ }
+ _ => &field.ty,
+ };
+
+ let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
+ let flag = *attrs.parser().kind == ParserKind::FromFlag;
+
+ let parser = attrs.parser();
+ let func = &parser.func;
+ let validator = match *parser.kind {
+ ParserKind::TryFromStr => quote_spanned! { func.span()=>
+ .validator(|s| {
+ #func(s.as_str())
+ .map(|_: #convert_type| ())
+ .map_err(|e| e.to_string())
+ })
+ },
+ ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
+ .validator_os(|s| #func(&s).map(|_: #convert_type| ()))
+ },
+ _ => quote!(),
+ };
+
+ let modifier = match **ty {
+ Ty::Bool => quote_spanned! { ty.span()=>
+ .takes_value(false)
+ .multiple(false)
+ },
+
+ Ty::Option => quote_spanned! { ty.span()=>
+ .takes_value(true)
+ .multiple(false)
+ #validator
+ },
+
+ Ty::OptionOption => quote_spanned! { ty.span()=>
+ .takes_value(true)
+ .multiple(false)
+ .min_values(0)
+ .max_values(1)
+ #validator
+ },
+
+ Ty::OptionVec => quote_spanned! { ty.span()=>
+ .takes_value(true)
+ .multiple(true)
+ .min_values(0)
+ #validator
+ },
+
+ Ty::Vec => quote_spanned! { ty.span()=>
+ .takes_value(true)
+ .multiple(true)
+ #validator
+ },
+
+ Ty::Other if occurrences => quote_spanned! { ty.span()=>
+ .takes_value(false)
+ .multiple(true)
+ },
+
+ Ty::Other if flag => quote_spanned! { ty.span()=>
+ .takes_value(false)
+ .multiple(false)
+ },
+
+ Ty::Other => {
+ let required = !attrs.has_method("default_value");
+ quote_spanned! { ty.span()=>
+ .takes_value(true)
+ .multiple(false)
+ .required(#required)
+ #validator
+ }
+ }
+ };
+
+ let name = attrs.cased_name();
+ let methods = attrs.field_methods();
+
+ Some(quote_spanned! { field.span()=>
+ let #app_var = #app_var.arg(
+ ::structopt::clap::Arg::with_name(#name)
+ #modifier
+ #methods
+ );
+ })
+ }
+ }
+ });
+
+ let app_methods = parent_attribute.top_level_methods();
+ quote! {{
+ let #app_var = #app_var#app_methods;
+ #( #args )*
+ #subcmd
+ #app_var
+ }}
+}
+
+fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
+ let fields = fields.iter().map(|field| {
+ let attrs = Attrs::from_field(
+ field,
+ parent_attribute.casing(),
+ parent_attribute.env_casing(),
+ );
+ let field_name = field.ident.as_ref().unwrap();
+ let kind = attrs.kind();
+ match &*kind {
+ Kind::Subcommand(ty) => {
+ let subcmd_type = match (**ty, sub_type(&field.ty)) {
+ (Ty::Option, Some(sub_type)) => sub_type,
+ _ => &field.ty,
+ };
+ let unwrapper = match **ty {
+ Ty::Option => quote!(),
+ _ => quote_spanned!( ty.span()=> .unwrap() ),
+ };
+ quote_spanned! { kind.span()=>
+ #field_name: <#subcmd_type as ::structopt::StructOptInternal>::from_subcommand(
+ matches.subcommand())
+ #unwrapper
+ }
+ }
+
+ Kind::FlattenStruct => quote_spanned! { kind.span()=>
+ #field_name: ::structopt::StructOpt::from_clap(matches)
+ },
+
+ Kind::Skip(val) => match val {
+ None => quote_spanned!(kind.span()=> #field_name: Default::default()),
+ Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
+ },
+
+ Kind::Arg(ty) => {
+ use crate::attrs::ParserKind::*;
+
+ let parser = attrs.parser();
+ let func = &parser.func;
+ let span = parser.kind.span();
+ let (value_of, values_of, parse) = match *parser.kind {
+ FromStr => (
+ quote_spanned!(span=> value_of),
+ quote_spanned!(span=> values_of),
+ func.clone(),
+ ),
+ TryFromStr => (
+ quote_spanned!(span=> value_of),
+ quote_spanned!(span=> values_of),
+ quote_spanned!(func.span()=> |s| #func(s).unwrap()),
+ ),
+ FromOsStr => (
+ quote_spanned!(span=> value_of_os),
+ quote_spanned!(span=> values_of_os),
+ func.clone(),
+ ),
+ TryFromOsStr => (
+ quote_spanned!(span=> value_of_os),
+ quote_spanned!(span=> values_of_os),
+ quote_spanned!(func.span()=> |s| #func(s).unwrap()),
+ ),
+ FromOccurrences => (
+ quote_spanned!(span=> occurrences_of),
+ quote!(),
+ func.clone(),
+ ),
+ FromFlag => (quote!(), quote!(), func.clone()),
+ };
+
+ let flag = *attrs.parser().kind == ParserKind::FromFlag;
+ let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
+ let name = attrs.cased_name();
+ let field_value = match **ty {
+ Ty::Bool => quote_spanned!(ty.span()=> matches.is_present(#name)),
+
+ Ty::Option => quote_spanned! { ty.span()=>
+ matches.#value_of(#name)
+ .map(#parse)
+ },
+
+ Ty::OptionOption => quote_spanned! { ty.span()=>
+ if matches.is_present(#name) {
+ Some(matches.#value_of(#name).map(#parse))
+ } else {
+ None
+ }
+ },
+
+ Ty::OptionVec => quote_spanned! { ty.span()=>
+ if matches.is_present(#name) {
+ Some(matches.#values_of(#name)
+ .map_or_else(Vec::new, |v| v.map(#parse).collect()))
+ } else {
+ None
+ }
+ },
+
+ Ty::Vec => quote_spanned! { ty.span()=>
+ matches.#values_of(#name)
+ .map_or_else(Vec::new, |v| v.map(#parse).collect())
+ },
+
+ Ty::Other if occurrences => quote_spanned! { ty.span()=>
+ #parse(matches.#value_of(#name))
+ },
+
+ Ty::Other if flag => quote_spanned! { ty.span()=>
+ #parse(matches.is_present(#name))
+ },
+
+ Ty::Other => quote_spanned! { ty.span()=>
+ matches.#value_of(#name)
+ .map(#parse)
+ .unwrap()
+ },
+ };
+
+ quote_spanned!(field.span()=> #field_name: #field_value )
+ }
+ }
+ });
+
+ quote! {{
+ #( #fields ),*
+ }}
+}
+
+fn gen_from_clap(
+ struct_name: &Ident,
+ fields: &Punctuated<Field, Comma>,
+ parent_attribute: &Attrs,
+) -> TokenStream {
+ let field_block = gen_constructor(fields, parent_attribute);
+
+ quote! {
+ fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
+ #struct_name #field_block
+ }
+ }
+}
+
+fn gen_clap(attrs: &[Attribute]) -> GenOutput {
+ let name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
+
+ let attrs = Attrs::from_struct(
+ Span::call_site(),
+ attrs,
+ Name::Assigned(LitStr::new(&name, Span::call_site())),
+ Sp::call_site(DEFAULT_CASING),
+ Sp::call_site(DEFAULT_ENV_CASING),
+ );
+ let tokens = {
+ let name = attrs.cased_name();
+ quote!(::structopt::clap::App::new(#name))
+ };
+
+ GenOutput { tokens, attrs }
+}
+
+fn gen_clap_struct(struct_attrs: &[Attribute]) -> GenOutput {
+ let initial_clap_app_gen = gen_clap(struct_attrs);
+ let clap_tokens = initial_clap_app_gen.tokens;
+
+ let augmented_tokens = quote! {
+ fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
+ let app = #clap_tokens;
+ <Self as ::structopt::StructOptInternal>::augment_clap(app)
+ }
+ };
+
+ GenOutput {
+ tokens: augmented_tokens,
+ attrs: initial_clap_app_gen.attrs,
+ }
+}
+
+fn gen_augment_clap(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
+ let app_var = Ident::new("app", Span::call_site());
+ let augmentation = gen_augmentation(fields, &app_var, parent_attribute);
+ quote! {
+ fn augment_clap<'a, 'b>(
+ #app_var: ::structopt::clap::App<'a, 'b>
+ ) -> ::structopt::clap::App<'a, 'b> {
+ #augmentation
+ }
+ }
+}
+
+fn gen_clap_enum(enum_attrs: &[Attribute]) -> GenOutput {
+ let initial_clap_app_gen = gen_clap(enum_attrs);
+ let clap_tokens = initial_clap_app_gen.tokens;
+
+ let tokens = quote! {
+ fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
+ let app = #clap_tokens
+ .setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp);
+ <Self as ::structopt::StructOptInternal>::augment_clap(app)
+ }
+ };
+
+ GenOutput {
+ tokens,
+ attrs: initial_clap_app_gen.attrs,
+ }
+}
+
+fn gen_augment_clap_enum(
+ variants: &Punctuated<Variant, Comma>,
+ parent_attribute: &Attrs,
+) -> TokenStream {
+ use syn::Fields::*;
+
+ let subcommands = variants.iter().map(|variant| {
+ let attrs = Attrs::from_struct(
+ variant.span(),
+ &variant.attrs,
+ Name::Derived(variant.ident.clone()),
+ parent_attribute.casing(),
+ parent_attribute.env_casing(),
+ );
+ let app_var = Ident::new("subcommand", Span::call_site());
+ let arg_block = match variant.fields {
+ Named(ref fields) => gen_augmentation(&fields.named, &app_var, &attrs),
+ Unit => quote!( #app_var ),
+ Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
+ let ty = &unnamed[0];
+ quote_spanned! { ty.span()=>
+ {
+ let #app_var = <#ty as ::structopt::StructOptInternal>::augment_clap(
+ #app_var
+ );
+ if <#ty as ::structopt::StructOptInternal>::is_subcommand() {
+ #app_var.setting(
+ ::structopt::clap::AppSettings::SubcommandRequiredElseHelp
+ )
+ } else {
+ #app_var
+ }
+ }
+ }
+ }
+ Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
+ };
+
+ let name = attrs.cased_name();
+ let from_attrs = attrs.top_level_methods();
+
+ quote! {
+ .subcommand({
+ let #app_var = ::structopt::clap::SubCommand::with_name(#name);
+ let #app_var = #arg_block;
+ #app_var#from_attrs
+ })
+ }
+ });
+
+ let app_methods = parent_attribute.top_level_methods();
+
+ quote! {
+ fn augment_clap<'a, 'b>(
+ app: ::structopt::clap::App<'a, 'b>
+ ) -> ::structopt::clap::App<'a, 'b> {
+ app #app_methods #( #subcommands )*
+ }
+ }
+}
+
+fn gen_from_clap_enum(name: &Ident) -> TokenStream {
+ quote! {
+ fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
+ <#name as ::structopt::StructOptInternal>::from_subcommand(matches.subcommand())
+ .unwrap()
+ }
+ }
+}
+
+fn gen_from_subcommand(
+ name: &Ident,
+ variants: &Punctuated<Variant, Comma>,
+ parent_attribute: &Attrs,
+) -> TokenStream {
+ use syn::Fields::*;
+
+ let match_arms = variants.iter().map(|variant| {
+ let attrs = Attrs::from_struct(
+ variant.span(),
+ &variant.attrs,
+ Name::Derived(variant.ident.clone()),
+ parent_attribute.casing(),
+ parent_attribute.env_casing(),
+ );
+ let sub_name = attrs.cased_name();
+ let variant_name = &variant.ident;
+ let constructor_block = match variant.fields {
+ Named(ref fields) => gen_constructor(&fields.named, &attrs),
+ Unit => quote!(),
+ Unnamed(ref fields) if fields.unnamed.len() == 1 => {
+ let ty = &fields.unnamed[0];
+ quote!( ( <#ty as ::structopt::StructOpt>::from_clap(matches) ) )
+ }
+ Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
+ };
+
+ quote! {
+ (#sub_name, Some(matches)) =>
+ Some(#name :: #variant_name #constructor_block)
+ }
+ });
+
+ quote! {
+ fn from_subcommand<'a, 'b>(
+ sub: (&'b str, Option<&'b ::structopt::clap::ArgMatches<'a>>)
+ ) -> Option<Self> {
+ match sub {
+ #( #match_arms ),*,
+ _ => None
+ }
+ }
+ }
+}
+
+#[cfg(feature = "paw")]
+fn gen_paw_impl(name: &Ident) -> TokenStream {
+ quote! {
+ impl paw::ParseArgs for #name {
+ type Error = std::io::Error;
+
+ fn parse_args() -> std::result::Result<Self, Self::Error> {
+ Ok(<#name as ::structopt::StructOpt>::from_args())
+ }
+ }
+ }
+}
+#[cfg(not(feature = "paw"))]
+fn gen_paw_impl(_: &Ident) -> TokenStream {
+ TokenStream::new()
+}
+
+fn impl_structopt_for_struct(
+ name: &Ident,
+ fields: &Punctuated<Field, Comma>,
+ attrs: &[Attribute],
+) -> TokenStream {
+ let basic_clap_app_gen = gen_clap_struct(attrs);
+ let augment_clap = gen_augment_clap(fields, &basic_clap_app_gen.attrs);
+ let from_clap = gen_from_clap(name, fields, &basic_clap_app_gen.attrs);
+ let paw_impl = gen_paw_impl(name);
+
+ let clap_tokens = basic_clap_app_gen.tokens;
+ quote! {
+ #[allow(unused_variables)]
+ #[allow(unknown_lints)]
+ #[allow(clippy::all)]
+ #[allow(dead_code, unreachable_code)]
+ impl ::structopt::StructOpt for #name {
+ #clap_tokens
+ #from_clap
+ }
+
+ #[allow(unused_variables)]
+ #[allow(unknown_lints)]
+ #[allow(clippy::all)]
+ #[allow(dead_code, unreachable_code)]
+ impl ::structopt::StructOptInternal for #name {
+ #augment_clap
+ fn is_subcommand() -> bool { false }
+ }
+
+ #paw_impl
+ }
+}
+
+fn impl_structopt_for_enum(
+ name: &Ident,
+ variants: &Punctuated<Variant, Comma>,
+ attrs: &[Attribute],
+) -> TokenStream {
+ let basic_clap_app_gen = gen_clap_enum(attrs);
+
+ let augment_clap = gen_augment_clap_enum(variants, &basic_clap_app_gen.attrs);
+ let from_clap = gen_from_clap_enum(name);
+ let from_subcommand = gen_from_subcommand(name, variants, &basic_clap_app_gen.attrs);
+ let paw_impl = gen_paw_impl(name);
+
+ let clap_tokens = basic_clap_app_gen.tokens;
+ quote! {
+ #[allow(unknown_lints)]
+ #[allow(unused_variables, dead_code, unreachable_code)]
+ #[allow(clippy)]
+ impl ::structopt::StructOpt for #name {
+ #clap_tokens
+ #from_clap
+ }
+
+ #[allow(unused_variables)]
+ #[allow(unknown_lints)]
+ #[allow(clippy::all)]
+ #[allow(dead_code, unreachable_code)]
+ impl ::structopt::StructOptInternal for #name {
+ #augment_clap
+ #from_subcommand
+ fn is_subcommand() -> bool { true }
+ }
+
+ #paw_impl
+ }
+}
+
+fn impl_structopt(input: &DeriveInput) -> TokenStream {
+ use syn::Data::*;
+
+ let struct_name = &input.ident;
+
+ set_dummy(quote! {
+ impl ::structopt::StructOpt for #struct_name {
+ fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
+ unimplemented!()
+ }
+ fn from_clap(_matches: &::structopt::clap::ArgMatches) -> Self {
+ unimplemented!()
+ }
+ }
+ });
+
+ match input.data {
+ Struct(DataStruct {
+ fields: syn::Fields::Named(ref fields),
+ ..
+ }) => impl_structopt_for_struct(struct_name, &fields.named, &input.attrs),
+ Enum(ref e) => impl_structopt_for_enum(struct_name, &e.variants, &input.attrs),
+ _ => abort_call_site!("structopt only supports non-tuple structs and enums"),
+ }
+}
diff --git a/structopt/structopt-derive/src/parse.rs b/structopt/structopt-derive/src/parse.rs
new file mode 100644
index 0000000..a704742
--- /dev/null
+++ b/structopt/structopt-derive/src/parse.rs
@@ -0,0 +1,304 @@
+use std::iter::FromIterator;
+
+use proc_macro_error::{abort, ResultExt};
+use quote::ToTokens;
+use syn::{
+ self, parenthesized,
+ parse::{Parse, ParseBuffer, ParseStream},
+ parse2,
+ punctuated::Punctuated,
+ spanned::Spanned,
+ Attribute, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Token,
+};
+
+pub struct StructOptAttributes {
+ pub paren_token: syn::token::Paren,
+ pub attrs: Punctuated<StructOptAttr, Token![,]>,
+}
+
+impl Parse for StructOptAttributes {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let attrs = content.parse_terminated(StructOptAttr::parse)?;
+
+ Ok(StructOptAttributes { paren_token, attrs })
+ }
+}
+
+pub enum StructOptAttr {
+ // single-identifier attributes
+ Short(Ident),
+ Long(Ident),
+ Env(Ident),
+ Flatten(Ident),
+ Subcommand(Ident),
+ NoVersion(Ident),
+ VerbatimDocComment(Ident),
+
+ // ident [= "string literal"]
+ About(Ident, Option<LitStr>),
+ Author(Ident, Option<LitStr>),
+
+ // ident = "string literal"
+ Version(Ident, LitStr),
+ RenameAllEnv(Ident, LitStr),
+ RenameAll(Ident, LitStr),
+ NameLitStr(Ident, LitStr),
+
+ // parse(parser_kind [= parser_func])
+ Parse(Ident, ParserSpec),
+
+ // ident [= arbitrary_expr]
+ Skip(Ident, Option<Expr>),
+
+ // ident = arbitrary_expr
+ NameExpr(Ident, Expr),
+
+ // ident(arbitrary_expr,*)
+ MethodCall(Ident, Vec<Expr>),
+}
+
+impl Parse for StructOptAttr {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ use self::StructOptAttr::*;
+
+ let name: Ident = input.parse()?;
+ let name_str = name.to_string();
+
+ if input.peek(Token![=]) {
+ // `name = value` attributes.
+ let assign_token = input.parse::<Token![=]>()?; // skip '='
+
+ if input.peek(LitStr) {
+ let lit: LitStr = input.parse()?;
+ let lit_str = lit.value();
+
+ let check_empty_lit = |s| {
+ if lit_str.is_empty() {
+ abort!(
+ lit.span(),
+ "`#[structopt({} = \"\")]` is deprecated in structopt 0.3, \
+ now it's default behavior",
+ s
+ );
+ }
+ };
+
+ match &*name_str.to_string() {
+ "rename_all" => Ok(RenameAll(name, lit)),
+ "rename_all_env" => Ok(RenameAllEnv(name, lit)),
+
+ "version" => {
+ check_empty_lit("version");
+ Ok(Version(name, lit))
+ }
+
+ "author" => {
+ check_empty_lit("author");
+ Ok(Author(name, Some(lit)))
+ }
+
+ "about" => {
+ check_empty_lit("about");
+ Ok(About(name, Some(lit)))
+ }
+
+ "skip" => {
+ let expr = ExprLit {
+ attrs: vec![],
+ lit: Lit::Str(lit),
+ };
+ let expr = Expr::Lit(expr);
+ Ok(Skip(name, Some(expr)))
+ }
+
+ _ => Ok(NameLitStr(name, lit)),
+ }
+ } else {
+ match input.parse::<Expr>() {
+ Ok(expr) => {
+ if name_str == "skip" {
+ Ok(Skip(name, Some(expr)))
+ } else {
+ Ok(NameExpr(name, expr))
+ }
+ }
+
+ Err(_) => abort! {
+ assign_token.span(),
+ "expected `string literal` or `expression` after `=`"
+ },
+ }
+ }
+ } else if input.peek(syn::token::Paren) {
+ // `name(...)` attributes.
+ let nested;
+ parenthesized!(nested in input);
+
+ match name_str.as_ref() {
+ "parse" => {
+ let parser_specs: Punctuated<ParserSpec, Token![,]> =
+ nested.parse_terminated(ParserSpec::parse)?;
+
+ if parser_specs.len() == 1 {
+ Ok(Parse(name, parser_specs[0].clone()))
+ } else {
+ abort!(name.span(), "parse must have exactly one argument")
+ }
+ }
+
+ "raw" => match nested.parse::<LitBool>() {
+ Ok(bool_token) => {
+ let expr = ExprLit {
+ attrs: vec![],
+ lit: Lit::Bool(bool_token),
+ };
+ let expr = Expr::Lit(expr);
+ Ok(MethodCall(name, vec![expr]))
+ }
+
+ Err(_) => {
+ abort!(name.span(),
+ "`#[structopt(raw(...))` attributes are removed in structopt 0.3, \
+ they are replaced with raw methods";
+ help = "if you meant to call `clap::Arg::raw()` method \
+ you should use bool literal, like `raw(true)` or `raw(false)`";
+ note = raw_method_suggestion(nested);
+ );
+ }
+ },
+
+ _ => {
+ let method_args: Punctuated<_, Token![,]> =
+ nested.parse_terminated(Expr::parse)?;
+ Ok(MethodCall(name, Vec::from_iter(method_args)))
+ }
+ }
+ } else {
+ // Attributes represented with a sole identifier.
+ match name_str.as_ref() {
+ "long" => Ok(Long(name)),
+ "short" => Ok(Short(name)),
+ "env" => Ok(Env(name)),
+ "flatten" => Ok(Flatten(name)),
+ "subcommand" => Ok(Subcommand(name)),
+ "no_version" => Ok(NoVersion(name)),
+ "verbatim_doc_comment" => Ok(VerbatimDocComment(name)),
+
+ "about" => (Ok(About(name, None))),
+ "author" => (Ok(Author(name, None))),
+
+ "skip" => Ok(Skip(name, None)),
+
+ "version" => abort!(
+ name.span(),
+ "#[structopt(version)] is invalid attribute, \
+ structopt 0.3 inherits version from Cargo.toml by default, \
+ no attribute needed"
+ ),
+
+ _ => abort!(name.span(), "unexpected attribute: {}", name_str),
+ }
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct ParserSpec {
+ pub kind: Ident,
+ pub eq_token: Option<Token![=]>,
+ pub parse_func: Option<Expr>,
+}
+
+impl Parse for ParserSpec {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let kind = input
+ .parse()
+ .map_err(|_| input.error("parser specification must start with identifier"))?;
+ let eq_token = input.parse()?;
+ let parse_func = match eq_token {
+ None => None,
+ Some(_) => Some(input.parse()?),
+ };
+ Ok(ParserSpec {
+ kind,
+ eq_token,
+ parse_func,
+ })
+ }
+}
+
+struct CommaSeparated<T>(Punctuated<T, Token![,]>);
+
+impl<T: Parse> Parse for CommaSeparated<T> {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let res = Punctuated::parse_separated_nonempty(input)?;
+ Ok(CommaSeparated(res))
+ }
+}
+
+fn raw_method_suggestion(ts: ParseBuffer) -> String {
+ let do_parse = move || -> Result<(Ident, CommaSeparated<Expr>), syn::Error> {
+ let name = ts.parse()?;
+ let _eq: Token![=] = ts.parse()?;
+ let val: LitStr = ts.parse()?;
+ Ok((name, syn::parse_str(&val.value())?))
+ };
+
+ fn to_string<T: ToTokens>(val: &T) -> String {
+ val.to_token_stream()
+ .to_string()
+ .replace(" ", "")
+ .replace(",", ", ")
+ }
+
+ if let Ok((name, val)) = do_parse() {
+ let exprs = val.0;
+ let suggestion = if exprs.len() == 1 {
+ let val = to_string(&exprs[0]);
+ format!(" = {}", val)
+ } else {
+ let val = exprs
+ .into_iter()
+ .map(|expr| to_string(&expr))
+ .collect::<Vec<_>>()
+ .join(", ");
+
+ format!("({})", val)
+ };
+
+ format!(
+ "if you need to call `clap::Arg/App::{}` method you \
+ can do it like this: #[structopt({}{})]",
+ name, name, suggestion
+ )
+ } else {
+ "if you need to call some method from `clap::Arg/App` \
+ you should use raw method, see \
+ https://docs.rs/structopt/0.3/structopt/#raw-methods"
+ .into()
+ }
+}
+
+pub fn parse_structopt_attributes(all_attrs: &[Attribute]) -> Vec<StructOptAttr> {
+ all_attrs
+ .iter()
+ .filter(|attr| attr.path.is_ident("structopt"))
+ .flat_map(|attr| {
+ let attrs: StructOptAttributes = parse2(attr.tokens.clone())
+ .map_err(|e| match &*e.to_string() {
+ // this error message is misleading and points to Span::call_site()
+ // so we patch it with something meaningful
+ "unexpected end of input, expected parentheses" => {
+ let span = attr.path.span();
+ let patch_msg = "expected parentheses after `structopt`";
+ syn::Error::new(span, patch_msg)
+ }
+ _ => e,
+ })
+ .unwrap_or_abort();
+ attrs.attrs
+ })
+ .collect()
+}
diff --git a/structopt/structopt-derive/src/spanned.rs b/structopt/structopt-derive/src/spanned.rs
new file mode 100644
index 0000000..2dd595b
--- /dev/null
+++ b/structopt/structopt-derive/src/spanned.rs
@@ -0,0 +1,101 @@
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::ToTokens;
+use std::ops::{Deref, DerefMut};
+use syn::LitStr;
+
+/// An entity with a span attached.
+#[derive(Debug, Clone)]
+pub struct Sp<T> {
+ span: Span,
+ val: T,
+}
+
+impl<T> Sp<T> {
+ pub fn new(val: T, span: Span) -> Self {
+ Sp { val, span }
+ }
+
+ pub fn call_site(val: T) -> Self {
+ Sp {
+ val,
+ span: Span::call_site(),
+ }
+ }
+
+ pub fn span(&self) -> Span {
+ self.span
+ }
+}
+
+impl<T: ToString> Sp<T> {
+ pub fn as_ident(&self) -> Ident {
+ Ident::new(&self.to_string(), self.span)
+ }
+
+ pub fn as_lit(&self) -> LitStr {
+ LitStr::new(&self.to_string(), self.span)
+ }
+}
+
+impl<T> Deref for Sp<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.val
+ }
+}
+
+impl<T> DerefMut for Sp<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ &mut self.val
+ }
+}
+
+impl From<Ident> for Sp<String> {
+ fn from(ident: Ident) -> Self {
+ Sp {
+ val: ident.to_string(),
+ span: ident.span(),
+ }
+ }
+}
+
+impl From<LitStr> for Sp<String> {
+ fn from(lit: LitStr) -> Self {
+ Sp {
+ val: lit.value(),
+ span: lit.span(),
+ }
+ }
+}
+
+impl<'a> From<Sp<&'a str>> for Sp<String> {
+ fn from(sp: Sp<&'a str>) -> Self {
+ Sp::new(sp.val.into(), sp.span)
+ }
+}
+
+impl<U, T: PartialEq<U>> PartialEq<U> for Sp<T> {
+ fn eq(&self, other: &U) -> bool {
+ self.val == *other
+ }
+}
+
+impl<T: AsRef<str>> AsRef<str> for Sp<T> {
+ fn as_ref(&self) -> &str {
+ self.val.as_ref()
+ }
+}
+
+impl<T: ToTokens> ToTokens for Sp<T> {
+ fn to_tokens(&self, stream: &mut TokenStream) {
+ // this is the simplest way out of correct ones to change span on
+ // arbitrary token tree I can come up with
+ let tt = self.val.to_token_stream().into_iter().map(|mut tt| {
+ tt.set_span(self.span.clone());
+ tt
+ });
+
+ stream.extend(tt);
+ }
+}
diff --git a/structopt/structopt-derive/src/ty.rs b/structopt/structopt-derive/src/ty.rs
new file mode 100644
index 0000000..06eb3ec
--- /dev/null
+++ b/structopt/structopt-derive/src/ty.rs
@@ -0,0 +1,108 @@
+//! Special types handling
+
+use crate::spanned::Sp;
+
+use syn::{
+ spanned::Spanned, GenericArgument, Path, PathArguments, PathArguments::AngleBracketed,
+ PathSegment, Type, TypePath,
+};
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Ty {
+ Bool,
+ Vec,
+ Option,
+ OptionOption,
+ OptionVec,
+ Other,
+}
+
+impl Ty {
+ pub fn from_syn_ty(ty: &syn::Type) -> Sp<Self> {
+ use Ty::*;
+ let t = |kind| Sp::new(kind, ty.span());
+
+ if is_simple_ty(ty, "bool") {
+ t(Bool)
+ } else if is_generic_ty(ty, "Vec") {
+ t(Vec)
+ } else if let Some(subty) = subty_if_name(ty, "Option") {
+ if is_generic_ty(subty, "Option") {
+ t(OptionOption)
+ } else if is_generic_ty(subty, "Vec") {
+ t(OptionVec)
+ } else {
+ t(Option)
+ }
+ } else {
+ t(Other)
+ }
+ }
+}
+
+pub fn sub_type(ty: &syn::Type) -> Option<&syn::Type> {
+ subty_if(ty, |_| true)
+}
+
+fn only_last_segment(ty: &syn::Type) -> Option<&PathSegment> {
+ match ty {
+ Type::Path(TypePath {
+ qself: None,
+ path:
+ Path {
+ leading_colon: None,
+ segments,
+ },
+ }) => only_one(segments.iter()),
+
+ _ => None,
+ }
+}
+
+fn subty_if<F>(ty: &syn::Type, f: F) -> Option<&syn::Type>
+where
+ F: FnOnce(&PathSegment) -> bool,
+{
+ only_last_segment(ty)
+ .filter(|segment| f(segment))
+ .and_then(|segment| {
+ if let AngleBracketed(args) = &segment.arguments {
+ only_one(args.args.iter()).and_then(|genneric| {
+ if let GenericArgument::Type(ty) = genneric {
+ Some(ty)
+ } else {
+ None
+ }
+ })
+ } else {
+ None
+ }
+ })
+}
+
+fn subty_if_name<'a>(ty: &'a syn::Type, name: &str) -> Option<&'a syn::Type> {
+ subty_if(ty, |seg| seg.ident == name)
+}
+
+fn is_simple_ty(ty: &syn::Type, name: &str) -> bool {
+ only_last_segment(ty)
+ .map(|segment| {
+ if let PathArguments::None = segment.arguments {
+ segment.ident == name
+ } else {
+ false
+ }
+ })
+ .unwrap_or(false)
+}
+
+fn is_generic_ty(ty: &syn::Type, name: &str) -> bool {
+ subty_if_name(ty, name).is_some()
+}
+
+fn only_one<I, T>(mut iter: I) -> Option<T>
+where
+ I: Iterator<Item = T>,
+{
+ iter.next().filter(|_| iter.next().is_none())
+}
diff --git a/structopt/tests/argument_naming.rs b/structopt/tests/argument_naming.rs
new file mode 100644
index 0000000..e7fe3d5
--- /dev/null
+++ b/structopt/tests/argument_naming.rs
@@ -0,0 +1,311 @@
+use structopt::StructOpt;
+
+#[test]
+fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ enum Opt {
+ Command { foo: u32 },
+ }
+
+ assert_eq!(
+ Opt::Command { foo: 0 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "command", "0"]))
+ );
+}
+
+#[test]
+fn test_multi_word_enum_variant_is_renamed() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ enum Opt {
+ FirstCommand { foo: u32 },
+ }
+
+ assert_eq!(
+ Opt::FirstCommand { foo: 0 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "first-command", "0"]))
+ );
+}
+
+#[test]
+fn test_standalone_long_generates_kebab_case() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[allow(non_snake_case)]
+ struct Opt {
+ #[structopt(long)]
+ FOO_OPTION: bool,
+ }
+
+ assert_eq!(
+ Opt { FOO_OPTION: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo-option"]))
+ );
+}
+
+#[test]
+fn test_custom_long_overwrites_default_name() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(long = "foo")]
+ foo_option: bool,
+ }
+
+ assert_eq!(
+ Opt { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"]))
+ );
+}
+
+#[test]
+fn test_standalone_long_uses_previous_defined_custom_name() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(name = "foo", long)]
+ foo_option: bool,
+ }
+
+ assert_eq!(
+ Opt { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"]))
+ );
+}
+
+#[test]
+fn test_standalone_long_ignores_afterwards_defined_custom_name() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(long, name = "foo")]
+ foo_option: bool,
+ }
+
+ assert_eq!(
+ Opt { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo-option"]))
+ );
+}
+
+#[test]
+fn test_standalone_short_generates_kebab_case() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[allow(non_snake_case)]
+ struct Opt {
+ #[structopt(short)]
+ FOO_OPTION: bool,
+ }
+
+ assert_eq!(
+ Opt { FOO_OPTION: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-f"]))
+ );
+}
+
+#[test]
+fn test_custom_short_overwrites_default_name() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(short = "o")]
+ foo_option: bool,
+ }
+
+ assert_eq!(
+ Opt { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-o"]))
+ );
+}
+
+#[test]
+fn test_standalone_short_uses_previous_defined_custom_name() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(name = "option", short)]
+ foo_option: bool,
+ }
+
+ assert_eq!(
+ Opt { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-o"]))
+ );
+}
+
+#[test]
+fn test_standalone_short_ignores_afterwards_defined_custom_name() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(short, name = "option")]
+ foo_option: bool,
+ }
+
+ assert_eq!(
+ Opt { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-f"]))
+ );
+}
+
+#[test]
+fn test_standalone_long_uses_previous_defined_casing() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(rename_all = "screaming_snake", long)]
+ foo_option: bool,
+ }
+
+ assert_eq!(
+ Opt { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--FOO_OPTION"]))
+ );
+}
+
+#[test]
+fn test_standalone_short_uses_previous_defined_casing() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(rename_all = "screaming_snake", short)]
+ foo_option: bool,
+ }
+
+ assert_eq!(
+ Opt { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-F"]))
+ );
+}
+
+#[test]
+fn test_standalone_long_works_with_verbatim_casing() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[allow(non_snake_case)]
+ struct Opt {
+ #[structopt(rename_all = "verbatim", long)]
+ _fOO_oPtiON: bool,
+ }
+
+ assert_eq!(
+ Opt { _fOO_oPtiON: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--_fOO_oPtiON"]))
+ );
+}
+
+#[test]
+fn test_standalone_short_works_with_verbatim_casing() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(rename_all = "verbatim", short)]
+ _foo: bool,
+ }
+
+ assert_eq!(
+ Opt { _foo: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-_"]))
+ );
+}
+
+#[test]
+fn test_rename_all_is_propagated_from_struct_to_fields() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[structopt(rename_all = "screaming_snake")]
+ struct Opt {
+ #[structopt(long)]
+ foo: bool,
+ }
+
+ assert_eq!(
+ Opt { foo: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--FOO"]))
+ );
+}
+
+#[test]
+fn test_rename_all_is_not_propagated_from_struct_into_flattened() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[structopt(rename_all = "screaming_snake")]
+ struct Opt {
+ #[structopt(flatten)]
+ foo: Foo,
+ }
+
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Foo {
+ #[structopt(long)]
+ foo: bool,
+ }
+
+ assert_eq!(
+ Opt {
+ foo: Foo { foo: true }
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"]))
+ );
+}
+
+#[test]
+fn test_rename_all_is_not_propagated_from_struct_into_subcommand() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[structopt(rename_all = "screaming_snake")]
+ struct Opt {
+ #[structopt(subcommand)]
+ foo: Foo,
+ }
+
+ #[derive(StructOpt, Debug, PartialEq)]
+ enum Foo {
+ Command {
+ #[structopt(long)]
+ foo: bool,
+ },
+ }
+
+ assert_eq!(
+ Opt {
+ foo: Foo::Command { foo: true }
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "command", "--foo"]))
+ );
+}
+
+#[test]
+fn test_rename_all_is_propagated_from_enum_to_variants_and_their_fields() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[structopt(rename_all = "screaming_snake")]
+ enum Opt {
+ FirstVariant,
+ SecondVariant {
+ #[structopt(long)]
+ foo: bool,
+ },
+ }
+
+ assert_eq!(
+ Opt::FirstVariant,
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "FIRST_VARIANT"]))
+ );
+
+ assert_eq!(
+ Opt::SecondVariant { foo: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "SECOND_VARIANT", "--FOO"]))
+ );
+}
+
+#[test]
+fn test_rename_all_is_propagation_can_be_overridden() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[structopt(rename_all = "screaming_snake")]
+ enum Opt {
+ #[structopt(rename_all = "kebab_case")]
+ FirstVariant {
+ #[structopt(long)]
+ foo_option: bool,
+ },
+ SecondVariant {
+ #[structopt(rename_all = "kebab_case", long)]
+ foo_option: bool,
+ },
+ }
+
+ assert_eq!(
+ Opt::FirstVariant { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "first-variant", "--foo-option"]))
+ );
+
+ assert_eq!(
+ Opt::SecondVariant { foo_option: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "SECOND_VARIANT", "--foo-option"]))
+ );
+}
diff --git a/structopt/tests/arguments.rs b/structopt/tests/arguments.rs
new file mode 100644
index 0000000..96a0938
--- /dev/null
+++ b/structopt/tests/arguments.rs
@@ -0,0 +1,86 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::clap;
+use structopt::StructOpt;
+
+#[test]
+fn required_argument() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ arg: i32,
+ }
+ assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test", "42"]));
+ assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "42", "24"])
+ .is_err());
+}
+
+#[test]
+fn optional_argument() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ arg: Option<i32>,
+ }
+ assert_eq!(Opt { arg: Some(42) }, Opt::from_iter(&["test", "42"]));
+ assert_eq!(Opt { arg: None }, Opt::from_iter(&["test"]));
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "42", "24"])
+ .is_err());
+}
+
+#[test]
+fn argument_with_default() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(default_value = "42")]
+ arg: i32,
+ }
+ assert_eq!(Opt { arg: 24 }, Opt::from_iter(&["test", "24"]));
+ assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test"]));
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "42", "24"])
+ .is_err());
+}
+
+#[test]
+fn arguments() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ arg: Vec<i32>,
+ }
+ assert_eq!(Opt { arg: vec![24] }, Opt::from_iter(&["test", "24"]));
+ assert_eq!(Opt { arg: vec![] }, Opt::from_iter(&["test"]));
+ assert_eq!(
+ Opt { arg: vec![24, 42] },
+ Opt::from_iter(&["test", "24", "42"])
+ );
+}
+
+#[test]
+fn arguments_safe() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ arg: Vec<i32>,
+ }
+ assert_eq!(
+ Opt { arg: vec![24] },
+ Opt::from_iter_safe(&["test", "24"]).unwrap()
+ );
+ assert_eq!(Opt { arg: vec![] }, Opt::from_iter_safe(&["test"]).unwrap());
+ assert_eq!(
+ Opt { arg: vec![24, 42] },
+ Opt::from_iter_safe(&["test", "24", "42"]).unwrap()
+ );
+
+ assert_eq!(
+ clap::ErrorKind::ValueValidation,
+ Opt::from_iter_safe(&["test", "NOPE"]).err().unwrap().kind
+ );
+}
diff --git a/structopt/tests/author_version_about.rs b/structopt/tests/author_version_about.rs
new file mode 100644
index 0000000..0c4a4fb
--- /dev/null
+++ b/structopt/tests/author_version_about.rs
@@ -0,0 +1,46 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[test]
+fn no_author_version_about() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ #[structopt(name = "foo", no_version)]
+ struct Opt {}
+
+ let output = get_long_help::<Opt>();
+ assert!(output.starts_with("foo \n\nUSAGE:"));
+}
+
+#[test]
+fn use_env() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ #[structopt(author, about)]
+ struct Opt {}
+
+ let output = get_long_help::<Opt>();
+ assert!(output.starts_with("structopt 0."));
+ assert!(output.contains("Guillaume Pinot <texitoi@texitoi.eu>, others"));
+ assert!(output.contains("Parse command line argument by defining a struct."));
+}
+
+#[test]
+fn explicit_version_not_str() {
+ const VERSION: &str = "custom version";
+
+ #[derive(StructOpt)]
+ #[structopt(version = VERSION)]
+ pub struct Opt {}
+
+ let output = get_long_help::<Opt>();
+ assert!(output.contains("custom version"));
+}
diff --git a/structopt/tests/custom-string-parsers.rs b/structopt/tests/custom-string-parsers.rs
new file mode 100644
index 0000000..89070ed
--- /dev/null
+++ b/structopt/tests/custom-string-parsers.rs
@@ -0,0 +1,306 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+use std::ffi::{CString, OsStr, OsString};
+use std::num::ParseIntError;
+use std::path::PathBuf;
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct PathOpt {
+ #[structopt(short, long, parse(from_os_str))]
+ path: PathBuf,
+
+ #[structopt(short, default_value = "../", parse(from_os_str))]
+ default_path: PathBuf,
+
+ #[structopt(short, parse(from_os_str))]
+ vector_path: Vec<PathBuf>,
+
+ #[structopt(short, parse(from_os_str))]
+ option_path_1: Option<PathBuf>,
+
+ #[structopt(short = "q", parse(from_os_str))]
+ option_path_2: Option<PathBuf>,
+}
+
+#[test]
+fn test_path_opt_simple() {
+ assert_eq!(
+ PathOpt {
+ path: PathBuf::from("/usr/bin"),
+ default_path: PathBuf::from("../"),
+ vector_path: vec![
+ PathBuf::from("/a/b/c"),
+ PathBuf::from("/d/e/f"),
+ PathBuf::from("/g/h/i"),
+ ],
+ option_path_1: None,
+ option_path_2: Some(PathBuf::from("j.zip")),
+ },
+ PathOpt::from_clap(&PathOpt::clap().get_matches_from(&[
+ "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q",
+ "j.zip",
+ ]))
+ );
+}
+
+fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
+ u64::from_str_radix(input, 16)
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct HexOpt {
+ #[structopt(short, parse(try_from_str = parse_hex))]
+ number: u64,
+}
+
+#[test]
+#[allow(clippy::unreadable_literal)]
+fn test_parse_hex() {
+ assert_eq!(
+ HexOpt { number: 5 },
+ HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "5"]))
+ );
+ assert_eq!(
+ HexOpt { number: 0xabcdef },
+ HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "abcdef"]))
+ );
+
+ let err = HexOpt::clap()
+ .get_matches_from_safe(&["test", "-n", "gg"])
+ .unwrap_err();
+ assert!(err.message.contains("invalid digit found in string"), err);
+}
+
+fn custom_parser_1(_: &str) -> &'static str {
+ "A"
+}
+fn custom_parser_2(_: &str) -> Result<&'static str, u32> {
+ Ok("B")
+}
+fn custom_parser_3(_: &OsStr) -> &'static str {
+ "C"
+}
+fn custom_parser_4(_: &OsStr) -> Result<&'static str, OsString> {
+ Ok("D")
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct NoOpOpt {
+ #[structopt(short, parse(from_str = custom_parser_1))]
+ a: &'static str,
+ #[structopt(short, parse(try_from_str = custom_parser_2))]
+ b: &'static str,
+ #[structopt(short, parse(from_os_str = custom_parser_3))]
+ c: &'static str,
+ #[structopt(short, parse(try_from_os_str = custom_parser_4))]
+ d: &'static str,
+}
+
+#[test]
+fn test_every_custom_parser() {
+ assert_eq!(
+ NoOpOpt {
+ a: "A",
+ b: "B",
+ c: "C",
+ d: "D"
+ },
+ NoOpOpt::from_clap(
+ &NoOpOpt::clap().get_matches_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"])
+ )
+ );
+}
+
+// Note: can't use `Vec<u8>` directly, as structopt would instead look for
+// conversion function from `&str` to `u8`.
+type Bytes = Vec<u8>;
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct DefaultedOpt {
+ #[structopt(short, parse(from_str))]
+ bytes: Bytes,
+
+ #[structopt(short, parse(try_from_str))]
+ integer: u64,
+
+ #[structopt(short, parse(from_os_str))]
+ path: PathBuf,
+}
+
+#[test]
+fn test_parser_with_default_value() {
+ assert_eq!(
+ DefaultedOpt {
+ bytes: b"E\xc2\xb2=p\xc2\xb2c\xc2\xb2+m\xc2\xb2c\xe2\x81\xb4".to_vec(),
+ integer: 9000,
+ path: PathBuf::from("src/lib.rs"),
+ },
+ DefaultedOpt::from_clap(&DefaultedOpt::clap().get_matches_from(&[
+ "test",
+ "-b",
+ "E²=p²c²+m²c⁴",
+ "-i",
+ "9000",
+ "-p",
+ "src/lib.rs",
+ ]))
+ );
+}
+
+#[derive(PartialEq, Debug)]
+struct Foo(u8);
+
+fn foo(value: u64) -> Foo {
+ Foo(value as u8)
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct Occurrences {
+ #[structopt(short, long, parse(from_occurrences))]
+ signed: i32,
+
+ #[structopt(short, parse(from_occurrences))]
+ little_signed: i8,
+
+ #[structopt(short, parse(from_occurrences))]
+ unsigned: usize,
+
+ #[structopt(short = "r", parse(from_occurrences))]
+ little_unsigned: u8,
+
+ #[structopt(short, long, parse(from_occurrences = foo))]
+ custom: Foo,
+}
+
+#[test]
+fn test_parser_occurrences() {
+ assert_eq!(
+ Occurrences {
+ signed: 3,
+ little_signed: 1,
+ unsigned: 0,
+ little_unsigned: 4,
+ custom: Foo(5),
+ },
+ Occurrences::from_clap(&Occurrences::clap().get_matches_from(&[
+ "test", "-s", "--signed", "--signed", "-l", "-rrrr", "-cccc", "--custom",
+ ]))
+ );
+}
+
+#[test]
+fn test_custom_bool() {
+ fn parse_bool(s: &str) -> Result<bool, String> {
+ match s {
+ "true" => Ok(true),
+ "false" => Ok(false),
+ _ => Err(format!("invalid bool {}", s)),
+ }
+ }
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, parse(try_from_str = parse_bool))]
+ debug: bool,
+ #[structopt(
+ short,
+ default_value = "false",
+ parse(try_from_str = parse_bool)
+ )]
+ verbose: bool,
+ #[structopt(short, parse(try_from_str = parse_bool))]
+ tribool: Option<bool>,
+ #[structopt(short, parse(try_from_str = parse_bool))]
+ bitset: Vec<bool>,
+ }
+
+ assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+ assert!(Opt::clap().get_matches_from_safe(&["test", "-d"]).is_err());
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-dfoo"])
+ .is_err());
+ assert_eq!(
+ Opt {
+ debug: false,
+ verbose: false,
+ tribool: None,
+ bitset: vec![],
+ },
+ Opt::from_iter(&["test", "-dfalse"])
+ );
+ assert_eq!(
+ Opt {
+ debug: true,
+ verbose: false,
+ tribool: None,
+ bitset: vec![],
+ },
+ Opt::from_iter(&["test", "-dtrue"])
+ );
+ assert_eq!(
+ Opt {
+ debug: true,
+ verbose: false,
+ tribool: None,
+ bitset: vec![],
+ },
+ Opt::from_iter(&["test", "-dtrue", "-vfalse"])
+ );
+ assert_eq!(
+ Opt {
+ debug: true,
+ verbose: true,
+ tribool: None,
+ bitset: vec![],
+ },
+ Opt::from_iter(&["test", "-dtrue", "-vtrue"])
+ );
+ assert_eq!(
+ Opt {
+ debug: true,
+ verbose: false,
+ tribool: Some(false),
+ bitset: vec![],
+ },
+ Opt::from_iter(&["test", "-dtrue", "-tfalse"])
+ );
+ assert_eq!(
+ Opt {
+ debug: true,
+ verbose: false,
+ tribool: Some(true),
+ bitset: vec![],
+ },
+ Opt::from_iter(&["test", "-dtrue", "-ttrue"])
+ );
+ assert_eq!(
+ Opt {
+ debug: true,
+ verbose: false,
+ tribool: None,
+ bitset: vec![false, true, false, false],
+ },
+ Opt::from_iter(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse", "-bfalse"])
+ );
+}
+
+#[test]
+fn test_cstring() {
+ #[derive(StructOpt)]
+ struct Opt {
+ #[structopt(parse(try_from_str = CString::new))]
+ c_string: CString,
+ }
+ assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+ assert_eq!(Opt::from_iter(&["test", "bla"]).c_string.to_bytes(), b"bla");
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "bla\0bla"])
+ .is_err());
+}
diff --git a/structopt/tests/deny-warnings.rs b/structopt/tests/deny-warnings.rs
new file mode 100644
index 0000000..721204a
--- /dev/null
+++ b/structopt/tests/deny-warnings.rs
@@ -0,0 +1,47 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(warnings)]
+
+use structopt::StructOpt;
+
+fn try_str(s: &str) -> Result<String, std::convert::Infallible> {
+ Ok(s.into())
+}
+
+#[test]
+fn warning_never_struct() {
+ #[derive(Debug, PartialEq, StructOpt)]
+ struct Opt {
+ #[structopt(parse(try_from_str = try_str))]
+ s: String,
+ }
+ assert_eq!(
+ Opt {
+ s: "foo".to_string()
+ },
+ Opt::from_iter(&["test", "foo"])
+ );
+}
+
+#[test]
+fn warning_never_enum() {
+ #[derive(Debug, PartialEq, StructOpt)]
+ enum Opt {
+ Foo {
+ #[structopt(parse(try_from_str = try_str))]
+ s: String,
+ },
+ }
+ assert_eq!(
+ Opt::Foo {
+ s: "foo".to_string()
+ },
+ Opt::from_iter(&["test", "foo", "foo"])
+ );
+}
diff --git a/structopt/tests/doc-comments-help.rs b/structopt/tests/doc-comments-help.rs
new file mode 100644
index 0000000..27649b8
--- /dev/null
+++ b/structopt/tests/doc-comments-help.rs
@@ -0,0 +1,162 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[test]
+fn doc_comments() {
+ /// Lorem ipsum
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct LoremIpsum {
+ /// Fooify a bar
+ /// and a baz
+ #[structopt(short, long)]
+ foo: bool,
+ }
+
+ let help = get_long_help::<LoremIpsum>();
+ assert!(help.contains("Lorem ipsum"));
+ assert!(help.contains("Fooify a bar and a baz"));
+}
+
+#[test]
+fn help_is_better_than_comments() {
+ /// Lorem ipsum
+ #[derive(StructOpt, PartialEq, Debug)]
+ #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")]
+ struct LoremIpsum {
+ /// Fooify a bar
+ #[structopt(short, long, help = "DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES")]
+ foo: bool,
+ }
+
+ let help = get_long_help::<LoremIpsum>();
+ assert!(help.contains("Dolor sit amet"));
+ assert!(!help.contains("Lorem ipsum"));
+ assert!(help.contains("DO NOT PASS A BAR"));
+}
+
+#[test]
+fn empty_line_in_doc_comment_is_double_linefeed() {
+ /// Foo.
+ ///
+ /// Bar
+ #[derive(StructOpt, PartialEq, Debug)]
+ #[structopt(name = "lorem-ipsum", no_version)]
+ struct LoremIpsum {}
+
+ let help = get_long_help::<LoremIpsum>();
+ assert!(help.starts_with("lorem-ipsum \nFoo.\n\nBar\n\nUSAGE:"));
+}
+
+#[test]
+fn field_long_doc_comment_both_help_long_help() {
+ /// Lorem ipsumclap
+ #[derive(StructOpt, PartialEq, Debug)]
+ #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")]
+ struct LoremIpsum {
+ /// Dot is removed from multiline comments.
+ ///
+ /// Long help
+ #[structopt(long)]
+ foo: bool,
+
+ /// Dot is removed from one short comment.
+ #[structopt(long)]
+ bar: bool,
+ }
+
+ let short_help = get_help::<LoremIpsum>();
+ let long_help = get_long_help::<LoremIpsum>();
+
+ assert!(short_help.contains("Dot is removed from one short comment"));
+ assert!(!short_help.contains("Dot is removed from one short comment."));
+ assert!(short_help.contains("Dot is removed from multiline comments"));
+ assert!(!short_help.contains("Dot is removed from multiline comments."));
+ assert!(long_help.contains("Long help"));
+ assert!(!short_help.contains("Long help"));
+}
+
+#[test]
+fn top_long_doc_comment_both_help_long_help() {
+ /// Lorem ipsumclap
+ #[derive(StructOpt, Debug)]
+ #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")]
+ struct LoremIpsum {
+ #[structopt(subcommand)]
+ foo: SubCommand,
+ }
+
+ #[derive(StructOpt, Debug)]
+ pub enum SubCommand {
+ /// DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES
+ ///
+ /// Or something else
+ Foo {
+ #[structopt(help = "foo")]
+ bars: Vec<String>,
+ },
+ }
+
+ let short_help = get_help::<LoremIpsum>();
+ let long_help = get_subcommand_long_help::<LoremIpsum>("foo");
+
+ assert!(!short_help.contains("Or something else"));
+ assert!(long_help.contains("DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES"));
+ assert!(long_help.contains("Or something else"));
+}
+
+#[test]
+fn verbatim_doc_comment() {
+ /// DANCE!
+ ///
+ /// ()
+ /// |
+ /// ( () )
+ /// ) ________ // )
+ /// () |\ \ //
+ /// ( \\__ \ ______\//
+ /// \__) | |
+ /// | | |
+ /// \ | |
+ /// \|_______|
+ /// // \\
+ /// (( ||
+ /// \\ ||
+ /// ( () ||
+ /// ( () ) )
+ #[derive(StructOpt, Debug)]
+ #[structopt(verbatim_doc_comment)]
+ struct SeeFigure1 {
+ #[structopt(long)]
+ foo: bool,
+ }
+
+ let help = get_long_help::<SeeFigure1>();
+ let sample = r#"
+ ()
+ |
+ ( () )
+ ) ________ // )
+ () |\ \ //
+( \\__ \ ______\//
+ \__) | |
+ | | |
+ \ | |
+ \|_______|
+ // \\
+ (( ||
+ \\ ||
+ ( () ||
+ ( () ) )"#;
+
+ assert!(help.contains(sample))
+}
diff --git a/structopt/tests/explicit_name_no_renaming.rs b/structopt/tests/explicit_name_no_renaming.rs
new file mode 100644
index 0000000..eff7a86
--- /dev/null
+++ b/structopt/tests/explicit_name_no_renaming.rs
@@ -0,0 +1,32 @@
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[test]
+fn explicit_short_long_no_rename() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short = ".", long = ".foo")]
+ foo: Vec<String>,
+ }
+
+ assert_eq!(
+ Opt {
+ foo: vec!["short".into(), "long".into()]
+ },
+ Opt::from_iter(&["test", "-.", "short", "--.foo", "long"])
+ );
+}
+
+#[test]
+fn explicit_name_no_rename() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(name = ".options")]
+ foo: Vec<String>,
+ }
+
+ let help = get_long_help::<Opt>();
+ assert!(help.contains("[.options]..."))
+}
diff --git a/structopt/tests/flags.rs b/structopt/tests/flags.rs
new file mode 100644
index 0000000..39a5dc3
--- /dev/null
+++ b/structopt/tests/flags.rs
@@ -0,0 +1,162 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn unique_flag() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, long)]
+ alice: bool,
+ }
+
+ assert_eq!(
+ Opt { alice: false },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+ assert_eq!(
+ Opt { alice: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+ );
+ assert_eq!(
+ Opt { alice: true },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice"]))
+ );
+ assert!(Opt::clap().get_matches_from_safe(&["test", "-i"]).is_err());
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a", "foo"])
+ .is_err());
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a", "-a"])
+ .is_err());
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a", "--alice"])
+ .is_err());
+}
+
+#[test]
+fn multiple_flag() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, long, parse(from_occurrences))]
+ alice: u64,
+ #[structopt(short, long, parse(from_occurrences))]
+ bob: u8,
+ }
+
+ assert_eq!(
+ Opt { alice: 0, bob: 0 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+ assert_eq!(
+ Opt { alice: 1, bob: 0 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+ );
+ assert_eq!(
+ Opt { alice: 2, bob: 0 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-a"]))
+ );
+ assert_eq!(
+ Opt { alice: 2, bob: 2 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--alice", "-bb"]))
+ );
+ assert_eq!(
+ Opt { alice: 3, bob: 1 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-aaa", "--bob"]))
+ );
+ assert!(Opt::clap().get_matches_from_safe(&["test", "-i"]).is_err());
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a", "foo"])
+ .is_err());
+}
+
+fn parse_from_flag(b: bool) -> std::sync::atomic::AtomicBool {
+ std::sync::atomic::AtomicBool::new(b)
+}
+
+#[test]
+fn non_bool_flags() {
+ #[derive(StructOpt, Debug)]
+ struct Opt {
+ #[structopt(short, long, parse(from_flag = parse_from_flag))]
+ alice: std::sync::atomic::AtomicBool,
+ #[structopt(short, long, parse(from_flag))]
+ bob: std::sync::atomic::AtomicBool,
+ }
+
+ let falsey = Opt::from_clap(&Opt::clap().get_matches_from(&["test"]));
+ assert!(!falsey.alice.load(std::sync::atomic::Ordering::Relaxed));
+ assert!(!falsey.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+ let alice = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]));
+ assert!(alice.alice.load(std::sync::atomic::Ordering::Relaxed));
+ assert!(!alice.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+ let bob = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b"]));
+ assert!(!bob.alice.load(std::sync::atomic::Ordering::Relaxed));
+ assert!(bob.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+ let both = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b", "-a"]));
+ assert!(both.alice.load(std::sync::atomic::Ordering::Relaxed));
+ assert!(both.bob.load(std::sync::atomic::Ordering::Relaxed));
+}
+
+#[test]
+fn combined_flags() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, long)]
+ alice: bool,
+ #[structopt(short, long, parse(from_occurrences))]
+ bob: u64,
+ }
+
+ assert_eq!(
+ Opt {
+ alice: false,
+ bob: 0
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+ assert_eq!(
+ Opt {
+ alice: true,
+ bob: 0
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+ );
+ assert_eq!(
+ Opt {
+ alice: true,
+ bob: 0
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+ );
+ assert_eq!(
+ Opt {
+ alice: false,
+ bob: 1
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b"]))
+ );
+ assert_eq!(
+ Opt {
+ alice: true,
+ bob: 1
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice", "--bob"]))
+ );
+ assert_eq!(
+ Opt {
+ alice: true,
+ bob: 4
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-bb", "-a", "-bb"]))
+ );
+}
diff --git a/structopt/tests/flatten.rs b/structopt/tests/flatten.rs
new file mode 100644
index 0000000..4983d86
--- /dev/null
+++ b/structopt/tests/flatten.rs
@@ -0,0 +1,95 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn flatten() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Common {
+ arg: i32,
+ }
+
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(flatten)]
+ common: Common,
+ }
+ assert_eq!(
+ Opt {
+ common: Common { arg: 42 }
+ },
+ Opt::from_iter(&["test", "42"])
+ );
+ assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "42", "24"])
+ .is_err());
+}
+
+#[test]
+#[should_panic]
+fn flatten_twice() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Common {
+ arg: i32,
+ }
+
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(flatten)]
+ c1: Common,
+ // Defines "arg" twice, so this should not work.
+ #[structopt(flatten)]
+ c2: Common,
+ }
+ Opt::from_iter(&["test", "42", "43"]);
+}
+
+#[test]
+fn flatten_in_subcommand() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Common {
+ arg: i32,
+ }
+
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Add {
+ #[structopt(short)]
+ interactive: bool,
+ #[structopt(flatten)]
+ common: Common,
+ }
+
+ #[derive(StructOpt, PartialEq, Debug)]
+ enum Opt {
+ Fetch {
+ #[structopt(short)]
+ all: bool,
+ #[structopt(flatten)]
+ common: Common,
+ },
+
+ Add(Add),
+ }
+
+ assert_eq!(
+ Opt::Fetch {
+ all: false,
+ common: Common { arg: 42 }
+ },
+ Opt::from_iter(&["test", "fetch", "42"])
+ );
+ assert_eq!(
+ Opt::Add(Add {
+ interactive: true,
+ common: Common { arg: 43 }
+ }),
+ Opt::from_iter(&["test", "add", "-i", "43"])
+ );
+}
diff --git a/structopt/tests/issues.rs b/structopt/tests/issues.rs
new file mode 100644
index 0000000..4d250ae
--- /dev/null
+++ b/structopt/tests/issues.rs
@@ -0,0 +1,67 @@
+// https://github.com/TeXitoi/structopt/issues/151
+// https://github.com/TeXitoi/structopt/issues/289
+
+#[test]
+fn issue_151() {
+ use structopt::{clap::ArgGroup, StructOpt};
+
+ #[derive(StructOpt, Debug)]
+ #[structopt(group = ArgGroup::with_name("verb").required(true).multiple(true))]
+ struct Opt {
+ #[structopt(long, group = "verb")]
+ foo: bool,
+ #[structopt(long, group = "verb")]
+ bar: bool,
+ }
+
+ #[derive(Debug, StructOpt)]
+ struct Cli {
+ #[structopt(flatten)]
+ a: Opt,
+ }
+
+ assert!(Cli::clap().get_matches_from_safe(&["test"]).is_err());
+ assert!(Cli::clap()
+ .get_matches_from_safe(&["test", "--foo"])
+ .is_ok());
+ assert!(Cli::clap()
+ .get_matches_from_safe(&["test", "--bar"])
+ .is_ok());
+ assert!(Cli::clap()
+ .get_matches_from_safe(&["test", "--zebra"])
+ .is_err());
+ assert!(Cli::clap()
+ .get_matches_from_safe(&["test", "--foo", "--bar"])
+ .is_ok());
+}
+
+#[test]
+fn issue_289() {
+ use structopt::{clap::AppSettings, StructOpt};
+
+ #[derive(StructOpt)]
+ #[structopt(setting = AppSettings::InferSubcommands)]
+ enum Args {
+ SomeCommand(SubSubCommand),
+ AnotherCommand,
+ }
+
+ #[derive(StructOpt)]
+ #[structopt(setting = AppSettings::InferSubcommands)]
+ enum SubSubCommand {
+ TestCommand,
+ }
+
+ assert!(Args::clap()
+ .get_matches_from_safe(&["test", "some-command", "test-command"])
+ .is_ok());
+ assert!(Args::clap()
+ .get_matches_from_safe(&["test", "some", "test-command"])
+ .is_ok());
+ assert!(Args::clap()
+ .get_matches_from_safe(&["test", "some-command", "test"])
+ .is_ok());
+ assert!(Args::clap()
+ .get_matches_from_safe(&["test", "some", "test"])
+ .is_ok());
+}
diff --git a/structopt/tests/macro-errors.rs b/structopt/tests/macro-errors.rs
new file mode 100644
index 0000000..ae4f5a2
--- /dev/null
+++ b/structopt/tests/macro-errors.rs
@@ -0,0 +1,13 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+
+#[rustversion::attr(any(not(stable), before(1.39)), ignore)]
+#[test]
+fn ui() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/*.rs");
+}
diff --git a/structopt/tests/nested-subcommands.rs b/structopt/tests/nested-subcommands.rs
new file mode 100644
index 0000000..1fbd166
--- /dev/null
+++ b/structopt/tests/nested-subcommands.rs
@@ -0,0 +1,193 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct Opt {
+ #[structopt(short, long)]
+ force: bool,
+ #[structopt(short, long, parse(from_occurrences))]
+ verbose: u64,
+ #[structopt(subcommand)]
+ cmd: Sub,
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Sub {
+ Fetch {},
+ Add {},
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct Opt2 {
+ #[structopt(short, long)]
+ force: bool,
+ #[structopt(short, long, parse(from_occurrences))]
+ verbose: u64,
+ #[structopt(subcommand)]
+ cmd: Option<Sub>,
+}
+
+#[test]
+fn test_no_cmd() {
+ let result = Opt::clap().get_matches_from_safe(&["test"]);
+ assert!(result.is_err());
+
+ assert_eq!(
+ Opt2 {
+ force: false,
+ verbose: 0,
+ cmd: None
+ },
+ Opt2::from_clap(&Opt2::clap().get_matches_from(&["test"]))
+ );
+}
+
+#[test]
+fn test_fetch() {
+ assert_eq!(
+ Opt {
+ force: false,
+ verbose: 3,
+ cmd: Sub::Fetch {}
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vvv", "fetch"]))
+ );
+ assert_eq!(
+ Opt {
+ force: true,
+ verbose: 0,
+ cmd: Sub::Fetch {}
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--force", "fetch"]))
+ );
+}
+
+#[test]
+fn test_add() {
+ assert_eq!(
+ Opt {
+ force: false,
+ verbose: 0,
+ cmd: Sub::Add {}
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))
+ );
+ assert_eq!(
+ Opt {
+ force: false,
+ verbose: 2,
+ cmd: Sub::Add {}
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vv", "add"]))
+ );
+}
+
+#[test]
+fn test_badinput() {
+ let result = Opt::clap().get_matches_from_safe(&["test", "badcmd"]);
+ assert!(result.is_err());
+ let result = Opt::clap().get_matches_from_safe(&["test", "add", "--verbose"]);
+ assert!(result.is_err());
+ let result = Opt::clap().get_matches_from_safe(&["test", "--badopt", "add"]);
+ assert!(result.is_err());
+ let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badopt"]);
+ assert!(result.is_err());
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct Opt3 {
+ #[structopt(short, long)]
+ all: bool,
+ #[structopt(subcommand)]
+ cmd: Sub2,
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Sub2 {
+ Foo {
+ file: String,
+ #[structopt(subcommand)]
+ cmd: Sub3,
+ },
+ Bar {},
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Sub3 {
+ Baz {},
+ Quux {},
+}
+
+#[test]
+fn test_subsubcommand() {
+ assert_eq!(
+ Opt3 {
+ all: true,
+ cmd: Sub2::Foo {
+ file: "lib.rs".to_string(),
+ cmd: Sub3::Quux {}
+ }
+ },
+ Opt3::from_clap(
+ &Opt3::clap().get_matches_from(&["test", "--all", "foo", "lib.rs", "quux"])
+ )
+ );
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum SubSubCmdWithOption {
+ Remote {
+ #[structopt(subcommand)]
+ cmd: Option<Remote>,
+ },
+ Stash {
+ #[structopt(subcommand)]
+ cmd: Stash,
+ },
+}
+#[derive(StructOpt, PartialEq, Debug)]
+enum Remote {
+ Add { name: String, url: String },
+ Remove { name: String },
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Stash {
+ Save,
+ Pop,
+}
+
+#[test]
+fn sub_sub_cmd_with_option() {
+ fn make(args: &[&str]) -> Option<SubSubCmdWithOption> {
+ SubSubCmdWithOption::clap()
+ .get_matches_from_safe(args)
+ .ok()
+ .map(|m| SubSubCmdWithOption::from_clap(&m))
+ }
+ assert_eq!(
+ Some(SubSubCmdWithOption::Remote { cmd: None }),
+ make(&["", "remote"])
+ );
+ assert_eq!(
+ Some(SubSubCmdWithOption::Remote {
+ cmd: Some(Remote::Add {
+ name: "origin".into(),
+ url: "http".into()
+ })
+ }),
+ make(&["", "remote", "add", "origin", "http"])
+ );
+ assert_eq!(
+ Some(SubSubCmdWithOption::Stash { cmd: Stash::Save }),
+ make(&["", "stash", "save"])
+ );
+ assert_eq!(None, make(&["", "stash"]));
+}
diff --git a/structopt/tests/non_literal_attributes.rs b/structopt/tests/non_literal_attributes.rs
new file mode 100644
index 0000000..75b6b71
--- /dev/null
+++ b/structopt/tests/non_literal_attributes.rs
@@ -0,0 +1,147 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::clap::AppSettings;
+use structopt::StructOpt;
+
+pub const DISPLAY_ORDER: usize = 2;
+
+// Check if the global settings compile
+#[derive(StructOpt, Debug, PartialEq, Eq)]
+#[structopt(global_settings = &[AppSettings::ColoredHelp])]
+struct Opt {
+ #[structopt(
+ long = "x",
+ display_order = DISPLAY_ORDER,
+ next_line_help = true,
+ default_value = "0",
+ require_equals = true
+ )]
+ x: i32,
+
+ #[structopt(short = "l", long = "level", aliases = &["set-level", "lvl"])]
+ level: String,
+
+ #[structopt(long("values"))]
+ values: Vec<i32>,
+
+ #[structopt(name = "FILE", requires_if("FILE", "values"))]
+ files: Vec<String>,
+}
+
+#[test]
+fn test_slice() {
+ assert_eq!(
+ Opt {
+ x: 0,
+ level: "1".to_string(),
+ files: Vec::new(),
+ values: vec![],
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1"]))
+ );
+ assert_eq!(
+ Opt {
+ x: 0,
+ level: "1".to_string(),
+ files: Vec::new(),
+ values: vec![],
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--level", "1"]))
+ );
+ assert_eq!(
+ Opt {
+ x: 0,
+ level: "1".to_string(),
+ files: Vec::new(),
+ values: vec![],
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--set-level", "1"]))
+ );
+ assert_eq!(
+ Opt {
+ x: 0,
+ level: "1".to_string(),
+ files: Vec::new(),
+ values: vec![],
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--lvl", "1"]))
+ );
+}
+
+#[test]
+fn test_multi_args() {
+ assert_eq!(
+ Opt {
+ x: 0,
+ level: "1".to_string(),
+ files: vec!["file".to_string()],
+ values: vec![],
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "file"]))
+ );
+ assert_eq!(
+ Opt {
+ x: 0,
+ level: "1".to_string(),
+ files: vec!["FILE".to_string()],
+ values: vec![1],
+ },
+ Opt::from_clap(
+ &Opt::clap().get_matches_from(&["test", "-l", "1", "--values", "1", "--", "FILE"]),
+ )
+ );
+}
+
+#[test]
+fn test_multi_args_fail() {
+ let result = Opt::clap().get_matches_from_safe(&["test", "-l", "1", "--", "FILE"]);
+ assert!(result.is_err());
+}
+
+#[test]
+fn test_bool() {
+ assert_eq!(
+ Opt {
+ x: 1,
+ level: "1".to_string(),
+ files: vec![],
+ values: vec![],
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "--x=1"]))
+ );
+ let result = Opt::clap().get_matches_from_safe(&["test", "-l", "1", "--x", "1"]);
+ assert!(result.is_err());
+}
+
+fn parse_hex(input: &str) -> Result<u64, std::num::ParseIntError> {
+ u64::from_str_radix(input, 16)
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct HexOpt {
+ #[structopt(short = "n", parse(try_from_str = parse_hex))]
+ number: u64,
+}
+
+#[test]
+fn test_parse_hex_function_path() {
+ assert_eq!(
+ HexOpt { number: 5 },
+ HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "5"]))
+ );
+ assert_eq!(
+ HexOpt { number: 0xabcdef },
+ HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "abcdef"]))
+ );
+
+ let err = HexOpt::clap()
+ .get_matches_from_safe(&["test", "-n", "gg"])
+ .unwrap_err();
+ assert!(err.message.contains("invalid digit found in string"), err);
+}
diff --git a/structopt/tests/options.rs b/structopt/tests/options.rs
new file mode 100644
index 0000000..803abb4
--- /dev/null
+++ b/structopt/tests/options.rs
@@ -0,0 +1,336 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn required_option() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, long)]
+ arg: i32,
+ }
+ assert_eq!(
+ Opt { arg: 42 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"]))
+ );
+ assert_eq!(
+ Opt { arg: 42 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "42"]))
+ );
+ assert_eq!(
+ Opt { arg: 42 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--arg", "42"]))
+ );
+ assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a42", "-a24"])
+ .is_err());
+}
+
+#[test]
+fn optional_option() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short)]
+ arg: Option<i32>,
+ }
+ assert_eq!(
+ Opt { arg: Some(42) },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"]))
+ );
+ assert_eq!(
+ Opt { arg: None },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a42", "-a24"])
+ .is_err());
+}
+
+#[test]
+fn option_with_default() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, default_value = "42")]
+ arg: i32,
+ }
+ assert_eq!(
+ Opt { arg: 24 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))
+ );
+ assert_eq!(
+ Opt { arg: 42 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a42", "-a24"])
+ .is_err());
+}
+
+#[test]
+fn option_with_raw_default() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, default_value = "42")]
+ arg: i32,
+ }
+ assert_eq!(
+ Opt { arg: 24 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))
+ );
+ assert_eq!(
+ Opt { arg: 42 },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a42", "-a24"])
+ .is_err());
+}
+
+#[test]
+fn options() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, long)]
+ arg: Vec<i32>,
+ }
+ assert_eq!(
+ Opt { arg: vec![24] },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))
+ );
+ assert_eq!(
+ Opt { arg: vec![] },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+ assert_eq!(
+ Opt { arg: vec![24, 42] },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24", "--arg", "42"]))
+ );
+}
+
+#[test]
+fn empy_default_value() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short, default_value = "")]
+ arg: String,
+ }
+ assert_eq!(Opt { arg: "".into() }, Opt::from_iter(&["test"]));
+ assert_eq!(
+ Opt { arg: "foo".into() },
+ Opt::from_iter(&["test", "-afoo"])
+ );
+}
+
+#[test]
+fn option_from_str() {
+ #[derive(Debug, PartialEq)]
+ struct A;
+
+ impl<'a> From<&'a str> for A {
+ fn from(_: &str) -> A {
+ A
+ }
+ }
+
+ #[derive(Debug, StructOpt, PartialEq)]
+ struct Opt {
+ #[structopt(parse(from_str))]
+ a: Option<A>,
+ }
+
+ assert_eq!(Opt { a: None }, Opt::from_iter(&["test"]));
+ assert_eq!(Opt { a: Some(A) }, Opt::from_iter(&["test", "foo"]));
+}
+
+#[test]
+fn optional_argument_for_optional_option() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short)]
+ #[allow(clippy::option_option)]
+ arg: Option<Option<i32>>,
+ }
+ assert_eq!(
+ Opt {
+ arg: Some(Some(42))
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"]))
+ );
+ assert_eq!(
+ Opt { arg: Some(None) },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+ );
+ assert_eq!(
+ Opt { arg: None },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+ assert!(Opt::clap()
+ .get_matches_from_safe(&["test", "-a42", "-a24"])
+ .is_err());
+}
+
+#[test]
+fn two_option_options() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ #[allow(clippy::option_option)]
+ struct Opt {
+ #[structopt(short)]
+ arg: Option<Option<i32>>,
+
+ #[structopt(long)]
+ field: Option<Option<String>>,
+ }
+ assert_eq!(
+ Opt {
+ arg: Some(Some(42)),
+ field: Some(Some("f".into()))
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42", "--field", "f"]))
+ );
+ assert_eq!(
+ Opt {
+ arg: Some(Some(42)),
+ field: Some(None)
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42", "--field"]))
+ );
+ assert_eq!(
+ Opt {
+ arg: Some(None),
+ field: Some(None)
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--field"]))
+ );
+ assert_eq!(
+ Opt {
+ arg: Some(None),
+ field: Some(Some("f".into()))
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--field", "f"]))
+ );
+ assert_eq!(
+ Opt {
+ arg: None,
+ field: Some(None)
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--field"]))
+ );
+ assert_eq!(
+ Opt {
+ arg: None,
+ field: None
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+}
+
+#[test]
+fn optional_vec() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short)]
+ arg: Option<Vec<i32>>,
+ }
+ assert_eq!(
+ Opt { arg: Some(vec![1]) },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1"]))
+ );
+
+ assert_eq!(
+ Opt {
+ arg: Some(vec![1, 2])
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2"]))
+ );
+
+ assert_eq!(
+ Opt {
+ arg: Some(vec![1, 2])
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2", "-a"]))
+ );
+
+ assert_eq!(
+ Opt {
+ arg: Some(vec![1, 2])
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a", "-a2"]))
+ );
+
+ assert_eq!(
+ Opt {
+ arg: Some(vec![1, 2])
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "2"]))
+ );
+
+ assert_eq!(
+ Opt {
+ arg: Some(vec![1, 2, 3])
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "2", "-a", "3"]))
+ );
+
+ assert_eq!(
+ Opt { arg: Some(vec![]) },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+ );
+
+ assert_eq!(
+ Opt { arg: Some(vec![]) },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-a"]))
+ );
+
+ assert_eq!(
+ Opt { arg: None },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+}
+
+#[test]
+fn two_optional_vecs() {
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(short)]
+ arg: Option<Vec<i32>>,
+
+ #[structopt(short)]
+ b: Option<Vec<i32>>,
+ }
+
+ assert_eq!(
+ Opt {
+ arg: Some(vec![1]),
+ b: Some(vec![])
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "-b"]))
+ );
+
+ assert_eq!(
+ Opt {
+ arg: Some(vec![1]),
+ b: Some(vec![])
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-b", "-a1"]))
+ );
+
+ assert_eq!(
+ Opt {
+ arg: Some(vec![1, 2]),
+ b: Some(vec![1, 2])
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2", "-b1", "-b2"]))
+ );
+
+ assert_eq!(
+ Opt { arg: None, b: None },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+ );
+}
diff --git a/structopt/tests/privacy.rs b/structopt/tests/privacy.rs
new file mode 100644
index 0000000..730bbce
--- /dev/null
+++ b/structopt/tests/privacy.rs
@@ -0,0 +1,32 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+mod options {
+ use super::StructOpt;
+
+ #[derive(Debug, StructOpt)]
+ pub struct Options {
+ #[structopt(subcommand)]
+ pub subcommand: super::subcommands::SubCommand,
+ }
+}
+
+mod subcommands {
+ use super::StructOpt;
+
+ #[derive(Debug, StructOpt)]
+ pub enum SubCommand {
+ /// foo
+ Foo {
+ /// foo
+ bars: Vec<String>,
+ },
+ }
+}
diff --git a/structopt/tests/raw_bool_literal.rs b/structopt/tests/raw_bool_literal.rs
new file mode 100644
index 0000000..faf8628
--- /dev/null
+++ b/structopt/tests/raw_bool_literal.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn raw_bool_literal() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ #[structopt(no_version, name = "raw_bool")]
+ struct Opt {
+ #[structopt(raw(false))]
+ a: String,
+ #[structopt(raw(true))]
+ b: String,
+ }
+
+ assert_eq!(
+ Opt {
+ a: "one".into(),
+ b: "--help".into()
+ },
+ Opt::from_iter(&["test", "one", "--", "--help"])
+ );
+}
diff --git a/structopt/tests/raw_idents.rs b/structopt/tests/raw_idents.rs
new file mode 100644
index 0000000..c00ff66
--- /dev/null
+++ b/structopt/tests/raw_idents.rs
@@ -0,0 +1,17 @@
+use structopt::StructOpt;
+
+#[test]
+fn raw_idents() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(short, long)]
+ r#type: Vec<String>,
+ }
+
+ assert_eq!(
+ Opt {
+ r#type: vec!["long".into(), "short".into()]
+ },
+ Opt::from_iter(&["test", "--type", "long", "-t", "short"])
+ );
+}
diff --git a/structopt/tests/rename_all_env.rs b/structopt/tests/rename_all_env.rs
new file mode 100644
index 0000000..1979e84
--- /dev/null
+++ b/structopt/tests/rename_all_env.rs
@@ -0,0 +1,46 @@
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[test]
+fn it_works() {
+ #[derive(Debug, PartialEq, StructOpt)]
+ #[structopt(rename_all_env = "kebab")]
+ struct BehaviorModel {
+ #[structopt(env)]
+ be_nice: String,
+ }
+
+ let help = get_help::<BehaviorModel>();
+ assert!(help.contains("[env: be-nice=]"));
+}
+
+#[test]
+fn default_is_screaming() {
+ #[derive(Debug, PartialEq, StructOpt)]
+ struct BehaviorModel {
+ #[structopt(env)]
+ be_nice: String,
+ }
+
+ let help = get_help::<BehaviorModel>();
+ assert!(help.contains("[env: BE_NICE=]"));
+}
+
+#[test]
+fn overridable() {
+ #[derive(Debug, PartialEq, StructOpt)]
+ #[structopt(rename_all_env = "kebab")]
+ struct BehaviorModel {
+ #[structopt(env)]
+ be_nice: String,
+
+ #[structopt(rename_all_env = "pascal", env)]
+ be_agressive: String,
+ }
+
+ let help = get_help::<BehaviorModel>();
+ assert!(help.contains("[env: be-nice=]"));
+ assert!(help.contains("[env: BeAgressive=]"));
+}
diff --git a/structopt/tests/skip.rs b/structopt/tests/skip.rs
new file mode 100644
index 0000000..47682d8
--- /dev/null
+++ b/structopt/tests/skip.rs
@@ -0,0 +1,148 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn skip_1() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(short)]
+ x: u32,
+ #[structopt(skip)]
+ s: u32,
+ }
+
+ assert!(Opt::from_iter_safe(&["test", "-x", "10", "20"]).is_err());
+ assert_eq!(
+ Opt::from_iter(&["test", "-x", "10"]),
+ Opt {
+ x: 10,
+ s: 0, // default
+ }
+ );
+}
+
+#[test]
+fn skip_2() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(short)]
+ x: u32,
+ #[structopt(skip)]
+ ss: String,
+ #[structopt(skip)]
+ sn: u8,
+ y: u32,
+ #[structopt(skip)]
+ sz: u16,
+ t: u32,
+ }
+
+ assert_eq!(
+ Opt::from_iter(&["test", "-x", "10", "20", "30"]),
+ Opt {
+ x: 10,
+ ss: String::from(""),
+ sn: 0,
+ y: 20,
+ sz: 0,
+ t: 30,
+ }
+ );
+}
+
+#[test]
+fn skip_enum() {
+ #[derive(Debug, PartialEq)]
+ #[allow(unused)]
+ enum Kind {
+ A,
+ B,
+ }
+
+ impl Default for Kind {
+ fn default() -> Self {
+ return Kind::B;
+ }
+ }
+
+ #[derive(StructOpt, Debug, PartialEq)]
+ pub struct Opt {
+ #[structopt(long, short)]
+ number: u32,
+ #[structopt(skip)]
+ k: Kind,
+ #[structopt(skip)]
+ v: Vec<u32>,
+ }
+
+ assert_eq!(
+ Opt::from_iter(&["test", "-n", "10"]),
+ Opt {
+ number: 10,
+ k: Kind::B,
+ v: vec![],
+ }
+ );
+}
+
+#[test]
+fn skip_help_doc_comments() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ pub struct Opt {
+ #[structopt(skip, help = "internal_stuff")]
+ a: u32,
+
+ #[structopt(skip, long_help = "internal_stuff\ndo not touch")]
+ b: u32,
+
+ /// Not meant to be used by clap.
+ ///
+ /// I want a default here.
+ #[structopt(skip)]
+ c: u32,
+
+ #[structopt(short, parse(try_from_str))]
+ n: u32,
+ }
+
+ assert_eq!(
+ Opt::from_iter(&["test", "-n", "10"]),
+ Opt {
+ n: 10,
+ a: 0,
+ b: 0,
+ c: 0,
+ }
+ );
+}
+
+#[test]
+fn skip_val() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ pub struct Opt {
+ #[structopt(long, short)]
+ number: u32,
+
+ #[structopt(skip = "key")]
+ k: String,
+
+ #[structopt(skip = vec![1, 2, 3])]
+ v: Vec<u32>,
+ }
+
+ assert_eq!(
+ Opt::from_iter(&["test", "-n", "10"]),
+ Opt {
+ number: 10,
+ k: "key".into(),
+ v: vec![1, 2, 3]
+ }
+ );
+}
diff --git a/structopt/tests/special_types.rs b/structopt/tests/special_types.rs
new file mode 100644
index 0000000..ffed5e2
--- /dev/null
+++ b/structopt/tests/special_types.rs
@@ -0,0 +1,73 @@
+//! Checks that types like `::std::option::Option` are not special
+
+use structopt::StructOpt;
+
+#[rustversion::since(1.37)]
+#[test]
+fn special_types_bool() {
+ mod inner {
+ #[allow(non_camel_case_types)]
+ #[derive(PartialEq, Debug)]
+ pub struct bool(pub String);
+
+ impl std::str::FromStr for self::bool {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(self::bool(s.into()))
+ }
+ }
+ };
+
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ arg: inner::bool,
+ }
+
+ assert_eq!(
+ Opt {
+ arg: inner::bool("success".into())
+ },
+ Opt::from_iter(&["test", "success"])
+ );
+}
+
+#[test]
+fn special_types_option() {
+ fn parser(s: &str) -> Option<String> {
+ Some(s.to_string())
+ }
+
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(parse(from_str = parser))]
+ arg: ::std::option::Option<String>,
+ }
+
+ assert_eq!(
+ Opt {
+ arg: Some("success".into())
+ },
+ Opt::from_iter(&["test", "success"])
+ );
+}
+
+#[test]
+fn special_types_vec() {
+ fn parser(s: &str) -> Vec<String> {
+ vec![s.to_string()]
+ }
+
+ #[derive(StructOpt, PartialEq, Debug)]
+ struct Opt {
+ #[structopt(parse(from_str = parser))]
+ arg: ::std::vec::Vec<String>,
+ }
+
+ assert_eq!(
+ Opt {
+ arg: vec!["success".into()]
+ },
+ Opt::from_iter(&["test", "success"])
+ );
+}
diff --git a/structopt/tests/subcommands.rs b/structopt/tests/subcommands.rs
new file mode 100644
index 0000000..170c0da
--- /dev/null
+++ b/structopt/tests/subcommands.rs
@@ -0,0 +1,213 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt {
+ /// Fetch stuff from GitHub
+ Fetch {
+ #[structopt(long)]
+ all: bool,
+ #[structopt(short, long)]
+ /// Overwrite local branches.
+ force: bool,
+ repo: String,
+ },
+
+ Add {
+ #[structopt(short, long)]
+ interactive: bool,
+ #[structopt(short, long)]
+ verbose: bool,
+ },
+}
+
+#[test]
+fn test_fetch() {
+ assert_eq!(
+ Opt::Fetch {
+ all: true,
+ force: false,
+ repo: "origin".to_string()
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "--all", "origin"]))
+ );
+ assert_eq!(
+ Opt::Fetch {
+ all: false,
+ force: true,
+ repo: "origin".to_string()
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "-f", "origin"]))
+ );
+}
+
+#[test]
+fn test_add() {
+ assert_eq!(
+ Opt::Add {
+ interactive: false,
+ verbose: false
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))
+ );
+ assert_eq!(
+ Opt::Add {
+ interactive: true,
+ verbose: true
+ },
+ Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add", "-i", "-v"]))
+ );
+}
+
+#[test]
+fn test_no_parse() {
+ let result = Opt::clap().get_matches_from_safe(&["test", "badcmd", "-i", "-v"]);
+ assert!(result.is_err());
+
+ let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badoption"]);
+ assert!(result.is_err());
+
+ let result = Opt::clap().get_matches_from_safe(&["test"]);
+ assert!(result.is_err());
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt2 {
+ DoSomething { arg: String },
+}
+
+#[test]
+/// This test is specifically to make sure that hyphenated subcommands get
+/// processed correctly.
+fn test_hyphenated_subcommands() {
+ assert_eq!(
+ Opt2::DoSomething {
+ arg: "blah".to_string()
+ },
+ Opt2::from_clap(&Opt2::clap().get_matches_from(&["test", "do-something", "blah"]))
+ );
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt3 {
+ Add,
+ Init,
+ Fetch,
+}
+
+#[test]
+fn test_null_commands() {
+ assert_eq!(
+ Opt3::Add,
+ Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "add"]))
+ );
+ assert_eq!(
+ Opt3::Init,
+ Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "init"]))
+ );
+ assert_eq!(
+ Opt3::Fetch,
+ Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "fetch"]))
+ );
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+#[structopt(about = "Not shown")]
+struct Add {
+ file: String,
+}
+/// Not shown
+#[derive(StructOpt, PartialEq, Debug)]
+struct Fetch {
+ remote: String,
+}
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt4 {
+ // Not shown
+ /// Add a file
+ Add(Add),
+ Init,
+ /// download history from remote
+ Fetch(Fetch),
+}
+
+#[test]
+fn test_tuple_commands() {
+ assert_eq!(
+ Opt4::Add(Add {
+ file: "f".to_string()
+ }),
+ Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "add", "f"]))
+ );
+ assert_eq!(
+ Opt4::Init,
+ Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "init"]))
+ );
+ assert_eq!(
+ Opt4::Fetch(Fetch {
+ remote: "origin".to_string()
+ }),
+ Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "fetch", "origin"]))
+ );
+
+ let output = get_long_help::<Opt4>();
+
+ assert!(output.contains("download history from remote"));
+ assert!(output.contains("Add a file"));
+ assert!(!output.contains("Not shown"));
+}
+
+#[test]
+fn enum_in_enum_subsubcommand() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ pub enum Opt {
+ Daemon(DaemonCommand),
+ }
+
+ #[derive(StructOpt, Debug, PartialEq)]
+ pub enum DaemonCommand {
+ Start,
+ Stop,
+ }
+
+ let result = Opt::clap().get_matches_from_safe(&["test"]);
+ assert!(result.is_err());
+
+ let result = Opt::clap().get_matches_from_safe(&["test", "daemon"]);
+ assert!(result.is_err());
+
+ let result = Opt::from_iter(&["test", "daemon", "start"]);
+ assert_eq!(Opt::Daemon(DaemonCommand::Start), result);
+}
+
+#[test]
+fn flatten_enum() {
+ #[derive(StructOpt, Debug, PartialEq)]
+ struct Opt {
+ #[structopt(flatten)]
+ sub_cmd: SubCmd,
+ }
+ #[derive(StructOpt, Debug, PartialEq)]
+ enum SubCmd {
+ Foo,
+ Bar,
+ }
+
+ assert!(Opt::from_iter_safe(&["test"]).is_err());
+ assert_eq!(
+ Opt::from_iter(&["test", "foo"]),
+ Opt {
+ sub_cmd: SubCmd::Foo
+ }
+ );
+}
diff --git a/structopt/tests/ui/bool_default_value.rs b/structopt/tests/ui/bool_default_value.rs
new file mode 100644
index 0000000..9bdb0c9
--- /dev/null
+++ b/structopt/tests/ui/bool_default_value.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(short, default_value = true)]
+ b: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/bool_default_value.stderr b/structopt/tests/ui/bool_default_value.stderr
new file mode 100644
index 0000000..1e26a2d
--- /dev/null
+++ b/structopt/tests/ui/bool_default_value.stderr
@@ -0,0 +1,5 @@
+error: default_value is meaningless for bool
+ --> $DIR/bool_default_value.rs:14:24
+ |
+14 | #[structopt(short, default_value = true)]
+ | ^^^^^^^^^^^^^
diff --git a/structopt/tests/ui/bool_required.rs b/structopt/tests/ui/bool_required.rs
new file mode 100644
index 0000000..018223c
--- /dev/null
+++ b/structopt/tests/ui/bool_required.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(short, required = true)]
+ b: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/bool_required.stderr b/structopt/tests/ui/bool_required.stderr
new file mode 100644
index 0000000..0b80d48
--- /dev/null
+++ b/structopt/tests/ui/bool_required.stderr
@@ -0,0 +1,5 @@
+error: required is meaningless for bool
+ --> $DIR/bool_required.rs:14:24
+ |
+14 | #[structopt(short, required = true)]
+ | ^^^^^^^^
diff --git a/structopt/tests/ui/flatten_and_doc.rs b/structopt/tests/ui/flatten_and_doc.rs
new file mode 100644
index 0000000..2dc154d
--- /dev/null
+++ b/structopt/tests/ui/flatten_and_doc.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct DaemonOpts {
+ #[structopt(short)]
+ user: String,
+ #[structopt(short)]
+ group: String,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ /// Opts.
+ #[structopt(flatten)]
+ opts: DaemonOpts,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/flatten_and_doc.stderr b/structopt/tests/ui/flatten_and_doc.stderr
new file mode 100644
index 0000000..2724dbb
--- /dev/null
+++ b/structopt/tests/ui/flatten_and_doc.stderr
@@ -0,0 +1,5 @@
+error: methods and doc comments are not allowed for flattened entry
+ --> $DIR/flatten_and_doc.rs:23:17
+ |
+23 | #[structopt(flatten)]
+ | ^^^^^^^
diff --git a/structopt/tests/ui/flatten_and_methods.rs b/structopt/tests/ui/flatten_and_methods.rs
new file mode 100644
index 0000000..ff1af2e
--- /dev/null
+++ b/structopt/tests/ui/flatten_and_methods.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct DaemonOpts {
+ #[structopt(short)]
+ user: String,
+ #[structopt(short)]
+ group: String,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(short, flatten)]
+ opts: DaemonOpts,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/flatten_and_methods.stderr b/structopt/tests/ui/flatten_and_methods.stderr
new file mode 100644
index 0000000..f058eb3
--- /dev/null
+++ b/structopt/tests/ui/flatten_and_methods.stderr
@@ -0,0 +1,5 @@
+error: methods and doc comments are not allowed for flattened entry
+ --> $DIR/flatten_and_methods.rs:22:24
+ |
+22 | #[structopt(short, flatten)]
+ | ^^^^^^^
diff --git a/structopt/tests/ui/flatten_and_parse.rs b/structopt/tests/ui/flatten_and_parse.rs
new file mode 100644
index 0000000..3317272
--- /dev/null
+++ b/structopt/tests/ui/flatten_and_parse.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct DaemonOpts {
+ #[structopt(short)]
+ user: String,
+ #[structopt(short)]
+ group: String,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(flatten, parse(from_occurrences))]
+ opts: DaemonOpts,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/flatten_and_parse.stderr b/structopt/tests/ui/flatten_and_parse.stderr
new file mode 100644
index 0000000..e217a84
--- /dev/null
+++ b/structopt/tests/ui/flatten_and_parse.stderr
@@ -0,0 +1,5 @@
+error: parse attribute is not allowed for flattened entry
+ --> $DIR/flatten_and_parse.rs:22:26
+ |
+22 | #[structopt(flatten, parse(from_occurrences))]
+ | ^^^^^
diff --git a/structopt/tests/ui/non_existent_attr.rs b/structopt/tests/ui/non_existent_attr.rs
new file mode 100644
index 0000000..96daf45
--- /dev/null
+++ b/structopt/tests/ui/non_existent_attr.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(short, non_existing_attribute = 1)]
+ debug: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/non_existent_attr.stderr b/structopt/tests/ui/non_existent_attr.stderr
new file mode 100644
index 0000000..17bb87f
--- /dev/null
+++ b/structopt/tests/ui/non_existent_attr.stderr
@@ -0,0 +1,5 @@
+error[E0599]: no method named `non_existing_attribute` found for type `clap::args::arg::Arg<'_, '_>` in the current scope
+ --> $DIR/non_existent_attr.rs:14:24
+ |
+14 | #[structopt(short, non_existing_attribute = 1)]
+ | ^^^^^^^^^^^^^^^^^^^^^^ method not found in `clap::args::arg::Arg<'_, '_>`
diff --git a/structopt/tests/ui/opt_opt_nonpositional.rs b/structopt/tests/ui/opt_opt_nonpositional.rs
new file mode 100644
index 0000000..2a08105
--- /dev/null
+++ b/structopt/tests/ui/opt_opt_nonpositional.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ n: Option<Option<u32>>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/opt_opt_nonpositional.stderr b/structopt/tests/ui/opt_opt_nonpositional.stderr
new file mode 100644
index 0000000..586bf7a
--- /dev/null
+++ b/structopt/tests/ui/opt_opt_nonpositional.stderr
@@ -0,0 +1,5 @@
+error: Option<Option<T>> type is meaningless for positional argument
+ --> $DIR/opt_opt_nonpositional.rs:14:8
+ |
+14 | n: Option<Option<u32>>,
+ | ^^^^^^
diff --git a/structopt/tests/ui/opt_vec_nonpositional.rs b/structopt/tests/ui/opt_vec_nonpositional.rs
new file mode 100644
index 0000000..0f6f078
--- /dev/null
+++ b/structopt/tests/ui/opt_vec_nonpositional.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ n: Option<Vec<u32>>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/opt_vec_nonpositional.stderr b/structopt/tests/ui/opt_vec_nonpositional.stderr
new file mode 100644
index 0000000..6f01de5
--- /dev/null
+++ b/structopt/tests/ui/opt_vec_nonpositional.stderr
@@ -0,0 +1,5 @@
+error: Option<Vec<T>> type is meaningless for positional argument
+ --> $DIR/opt_vec_nonpositional.rs:14:8
+ |
+14 | n: Option<Vec<u32>>,
+ | ^^^^^^
diff --git a/structopt/tests/ui/option_default_value.rs b/structopt/tests/ui/option_default_value.rs
new file mode 100644
index 0000000..a86bc0e
--- /dev/null
+++ b/structopt/tests/ui/option_default_value.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(short, default_value = 1)]
+ n: Option<u32>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/option_default_value.stderr b/structopt/tests/ui/option_default_value.stderr
new file mode 100644
index 0000000..2215497
--- /dev/null
+++ b/structopt/tests/ui/option_default_value.stderr
@@ -0,0 +1,5 @@
+error: default_value is meaningless for Option
+ --> $DIR/option_default_value.rs:14:24
+ |
+14 | #[structopt(short, default_value = 1)]
+ | ^^^^^^^^^^^^^
diff --git a/structopt/tests/ui/option_required.rs b/structopt/tests/ui/option_required.rs
new file mode 100644
index 0000000..d91afbf
--- /dev/null
+++ b/structopt/tests/ui/option_required.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(short, required = true)]
+ n: Option<u32>,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/option_required.stderr b/structopt/tests/ui/option_required.stderr
new file mode 100644
index 0000000..0230d57
--- /dev/null
+++ b/structopt/tests/ui/option_required.stderr
@@ -0,0 +1,5 @@
+error: required is meaningless for Option
+ --> $DIR/option_required.rs:14:24
+ |
+14 | #[structopt(short, required = true)]
+ | ^^^^^^^^
diff --git a/structopt/tests/ui/parse_empty_try_from_os.rs b/structopt/tests/ui/parse_empty_try_from_os.rs
new file mode 100644
index 0000000..acfef0b
--- /dev/null
+++ b/structopt/tests/ui/parse_empty_try_from_os.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(parse(try_from_os_str))]
+ s: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/parse_empty_try_from_os.stderr b/structopt/tests/ui/parse_empty_try_from_os.stderr
new file mode 100644
index 0000000..3dc9f24
--- /dev/null
+++ b/structopt/tests/ui/parse_empty_try_from_os.stderr
@@ -0,0 +1,5 @@
+error: you must set parser for `try_from_os_str` explicitly
+ --> $DIR/parse_empty_try_from_os.rs:14:23
+ |
+14 | #[structopt(parse(try_from_os_str))]
+ | ^^^^^^^^^^^^^^^
diff --git a/structopt/tests/ui/parse_function_is_not_path.rs b/structopt/tests/ui/parse_function_is_not_path.rs
new file mode 100644
index 0000000..5eebc57
--- /dev/null
+++ b/structopt/tests/ui/parse_function_is_not_path.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(parse(from_str = "2"))]
+ s: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/parse_function_is_not_path.stderr b/structopt/tests/ui/parse_function_is_not_path.stderr
new file mode 100644
index 0000000..7cf7444
--- /dev/null
+++ b/structopt/tests/ui/parse_function_is_not_path.stderr
@@ -0,0 +1,5 @@
+error: `parse` argument must be a function path
+ --> $DIR/parse_function_is_not_path.rs:14:34
+ |
+14 | #[structopt(parse(from_str = "2"))]
+ | ^^^
diff --git a/structopt/tests/ui/parse_literal_spec.rs b/structopt/tests/ui/parse_literal_spec.rs
new file mode 100644
index 0000000..b6f125a
--- /dev/null
+++ b/structopt/tests/ui/parse_literal_spec.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(parse("from_str"))]
+ s: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/parse_literal_spec.stderr b/structopt/tests/ui/parse_literal_spec.stderr
new file mode 100644
index 0000000..6e99e8b
--- /dev/null
+++ b/structopt/tests/ui/parse_literal_spec.stderr
@@ -0,0 +1,5 @@
+error: parser specification must start with identifier
+ --> $DIR/parse_literal_spec.rs:14:23
+ |
+14 | #[structopt(parse("from_str"))]
+ | ^^^^^^^^^^
diff --git a/structopt/tests/ui/parse_not_zero_args.rs b/structopt/tests/ui/parse_not_zero_args.rs
new file mode 100644
index 0000000..8729178
--- /dev/null
+++ b/structopt/tests/ui/parse_not_zero_args.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt(parse(from_str, from_str))]
+ s: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/parse_not_zero_args.stderr b/structopt/tests/ui/parse_not_zero_args.stderr
new file mode 100644
index 0000000..11abe06
--- /dev/null
+++ b/structopt/tests/ui/parse_not_zero_args.stderr
@@ -0,0 +1,5 @@
+error: parse must have exactly one argument
+ --> $DIR/parse_not_zero_args.rs:14:17
+ |
+14 | #[structopt(parse(from_str, from_str))]
+ | ^^^^^
diff --git a/structopt/tests/ui/positional_bool.rs b/structopt/tests/ui/positional_bool.rs
new file mode 100644
index 0000000..4dbf538
--- /dev/null
+++ b/structopt/tests/ui/positional_bool.rs
@@ -0,0 +1,10 @@
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+ verbose: bool,
+}
+
+fn main() {
+ Opt::from_args();
+} \ No newline at end of file
diff --git a/structopt/tests/ui/positional_bool.stderr b/structopt/tests/ui/positional_bool.stderr
new file mode 100644
index 0000000..c3ed1ad
--- /dev/null
+++ b/structopt/tests/ui/positional_bool.stderr
@@ -0,0 +1,10 @@
+error: `bool` cannot be used as positional parameter with default parser
+
+ = help: if you want to create a flag add `long` or `short`
+ = help: If you really want a boolean parameter add an explicit parser, for example `parse(try_from_str)`
+ = note: see also https://github.com/TeXitoi/structopt/tree/master/examples/true_or_false.rs
+
+ --> $DIR/positional_bool.rs:5:14
+ |
+5 | verbose: bool,
+ | ^^^^
diff --git a/structopt/tests/ui/raw.rs b/structopt/tests/ui/raw.rs
new file mode 100644
index 0000000..b94f783
--- /dev/null
+++ b/structopt/tests/ui/raw.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+ #[structopt(raw(case_insensitive = "true"))]
+ s: String,
+}
+
+#[derive(StructOpt, Debug)]
+struct Opt2 {
+ #[structopt(raw(requires_if = r#""one", "two""#))]
+ s: String,
+}
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/raw.stderr b/structopt/tests/ui/raw.stderr
new file mode 100644
index 0000000..93b5e38
--- /dev/null
+++ b/structopt/tests/ui/raw.stderr
@@ -0,0 +1,19 @@
+error: `#[structopt(raw(...))` attributes are removed in structopt 0.3, they are replaced with raw methods
+
+ = help: if you meant to call `clap::Arg::raw()` method you should use bool literal, like `raw(true)` or `raw(false)`
+ = note: if you need to call `clap::Arg/App::case_insensitive` method you can do it like this: #[structopt(case_insensitive = true)]
+
+ --> $DIR/raw.rs:13:17
+ |
+13 | #[structopt(raw(case_insensitive = "true"))]
+ | ^^^
+
+error: `#[structopt(raw(...))` attributes are removed in structopt 0.3, they are replaced with raw methods
+
+ = help: if you meant to call `clap::Arg::raw()` method you should use bool literal, like `raw(true)` or `raw(false)`
+ = note: if you need to call `clap::Arg/App::requires_if` method you can do it like this: #[structopt(requires_if("one", "two"))]
+
+ --> $DIR/raw.rs:19:17
+ |
+19 | #[structopt(raw(requires_if = r#""one", "two""#))]
+ | ^^^
diff --git a/structopt/tests/ui/rename_all_wrong_casing.rs b/structopt/tests/ui/rename_all_wrong_casing.rs
new file mode 100644
index 0000000..4dabe14
--- /dev/null
+++ b/structopt/tests/ui/rename_all_wrong_casing.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic", rename_all = "fail")]
+struct Opt {
+ #[structopt(short)]
+ s: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/rename_all_wrong_casing.stderr b/structopt/tests/ui/rename_all_wrong_casing.stderr
new file mode 100644
index 0000000..2a72080
--- /dev/null
+++ b/structopt/tests/ui/rename_all_wrong_casing.stderr
@@ -0,0 +1,5 @@
+error: unsupported casing: `fail`
+ --> $DIR/rename_all_wrong_casing.rs:12:42
+ |
+12 | #[structopt(name = "basic", rename_all = "fail")]
+ | ^^^^^^
diff --git a/structopt/tests/ui/skip_flatten.rs b/structopt/tests/ui/skip_flatten.rs
new file mode 100644
index 0000000..8668ec2
--- /dev/null
+++ b/structopt/tests/ui/skip_flatten.rs
@@ -0,0 +1,42 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+ #[structopt(short)]
+ s: String,
+
+ #[structopt(skip, flatten)]
+ cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+ #[structopt(name = "pound")]
+ /// Pound acorns into flour for cookie dough.
+ Pound { acorns: u32 },
+
+ Sparkle {
+ #[structopt(short)]
+ color: String,
+ },
+}
+
+impl Default for Command {
+ fn default() -> Self {
+ Command::Pound { acorns: 0 }
+ }
+}
+
+fn main() {
+ let opt = MakeCookie::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/skip_flatten.stderr b/structopt/tests/ui/skip_flatten.stderr
new file mode 100644
index 0000000..76477a3
--- /dev/null
+++ b/structopt/tests/ui/skip_flatten.stderr
@@ -0,0 +1,5 @@
+error: subcommand, flatten and skip cannot be used together
+ --> $DIR/skip_flatten.rs:17:23
+ |
+17 | #[structopt(skip, flatten)]
+ | ^^^^^^^
diff --git a/structopt/tests/ui/skip_subcommand.rs b/structopt/tests/ui/skip_subcommand.rs
new file mode 100644
index 0000000..5d21426
--- /dev/null
+++ b/structopt/tests/ui/skip_subcommand.rs
@@ -0,0 +1,42 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+ #[structopt(short)]
+ s: String,
+
+ #[structopt(subcommand, skip)]
+ cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+ #[structopt(name = "pound")]
+ /// Pound acorns into flour for cookie dough.
+ Pound { acorns: u32 },
+
+ Sparkle {
+ #[structopt(short)]
+ color: String,
+ },
+}
+
+impl Default for Command {
+ fn default() -> Self {
+ Command::Pound { acorns: 0 }
+ }
+}
+
+fn main() {
+ let opt = MakeCookie::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/skip_subcommand.stderr b/structopt/tests/ui/skip_subcommand.stderr
new file mode 100644
index 0000000..aba2d69
--- /dev/null
+++ b/structopt/tests/ui/skip_subcommand.stderr
@@ -0,0 +1,5 @@
+error: subcommand, flatten and skip cannot be used together
+ --> $DIR/skip_subcommand.rs:17:29
+ |
+17 | #[structopt(subcommand, skip)]
+ | ^^^^
diff --git a/structopt/tests/ui/skip_with_other_options.rs b/structopt/tests/ui/skip_with_other_options.rs
new file mode 100644
index 0000000..73c5342
--- /dev/null
+++ b/structopt/tests/ui/skip_with_other_options.rs
@@ -0,0 +1,15 @@
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "test")]
+pub struct Opt {
+ #[structopt(long)]
+ a: u32,
+ #[structopt(skip, long)]
+ b: u32,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/skip_with_other_options.stderr b/structopt/tests/ui/skip_with_other_options.stderr
new file mode 100644
index 0000000..3345f92
--- /dev/null
+++ b/structopt/tests/ui/skip_with_other_options.stderr
@@ -0,0 +1,5 @@
+error: methods are not allowed for skipped fields
+ --> $DIR/skip_with_other_options.rs:8:17
+ |
+8 | #[structopt(skip, long)]
+ | ^^^^
diff --git a/structopt/tests/ui/skip_without_default.rs b/structopt/tests/ui/skip_without_default.rs
new file mode 100644
index 0000000..bc47511
--- /dev/null
+++ b/structopt/tests/ui/skip_without_default.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(Debug)]
+enum Kind {
+ A,
+ B,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "test")]
+pub struct Opt {
+ #[structopt(short)]
+ number: u32,
+ #[structopt(skip)]
+ k: Kind,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/skip_without_default.stderr b/structopt/tests/ui/skip_without_default.stderr
new file mode 100644
index 0000000..330898f
--- /dev/null
+++ b/structopt/tests/ui/skip_without_default.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `Kind: std::default::Default` is not satisfied
+ --> $DIR/skip_without_default.rs:22:17
+ |
+22 | #[structopt(skip)]
+ | ^^^^ the trait `std::default::Default` is not implemented for `Kind`
+ |
+ = note: required by `std::default::Default::default`
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/structopt/tests/ui/struct_flatten.rs b/structopt/tests/ui/struct_flatten.rs
new file mode 100644
index 0000000..2b205f1
--- /dev/null
+++ b/structopt/tests/ui/struct_flatten.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic", flatten)]
+struct Opt {
+ #[structopt(short)]
+ s: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/struct_flatten.stderr b/structopt/tests/ui/struct_flatten.stderr
new file mode 100644
index 0000000..7f0fc6d
--- /dev/null
+++ b/structopt/tests/ui/struct_flatten.stderr
@@ -0,0 +1,5 @@
+error: flatten is only allowed on fields
+ --> $DIR/struct_flatten.rs:12:29
+ |
+12 | #[structopt(name = "basic", flatten)]
+ | ^^^^^^^
diff --git a/structopt/tests/ui/struct_parse.rs b/structopt/tests/ui/struct_parse.rs
new file mode 100644
index 0000000..e428b23
--- /dev/null
+++ b/structopt/tests/ui/struct_parse.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic", parse(from_str))]
+struct Opt {
+ #[structopt(short)]
+ s: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/struct_parse.stderr b/structopt/tests/ui/struct_parse.stderr
new file mode 100644
index 0000000..5518214
--- /dev/null
+++ b/structopt/tests/ui/struct_parse.stderr
@@ -0,0 +1,5 @@
+error: `parse` attribute is only allowed on fields
+ --> $DIR/struct_parse.rs:12:29
+ |
+12 | #[structopt(name = "basic", parse(from_str))]
+ | ^^^^^
diff --git a/structopt/tests/ui/struct_subcommand.rs b/structopt/tests/ui/struct_subcommand.rs
new file mode 100644
index 0000000..ac0b145
--- /dev/null
+++ b/structopt/tests/ui/struct_subcommand.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic", subcommand)]
+struct Opt {
+ #[structopt(short)]
+ s: String,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/struct_subcommand.stderr b/structopt/tests/ui/struct_subcommand.stderr
new file mode 100644
index 0000000..438f6f8
--- /dev/null
+++ b/structopt/tests/ui/struct_subcommand.stderr
@@ -0,0 +1,5 @@
+error: subcommand is only allowed on fields
+ --> $DIR/struct_subcommand.rs:12:29
+ |
+12 | #[structopt(name = "basic", subcommand)]
+ | ^^^^^^^^^^
diff --git a/structopt/tests/ui/structopt_empty_attr.rs b/structopt/tests/ui/structopt_empty_attr.rs
new file mode 100644
index 0000000..a7fc0b9
--- /dev/null
+++ b/structopt/tests/ui/structopt_empty_attr.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt]
+ debug: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
+
diff --git a/structopt/tests/ui/structopt_empty_attr.stderr b/structopt/tests/ui/structopt_empty_attr.stderr
new file mode 100644
index 0000000..dde3630
--- /dev/null
+++ b/structopt/tests/ui/structopt_empty_attr.stderr
@@ -0,0 +1,5 @@
+error: expected parentheses after `structopt`
+ --> $DIR/structopt_empty_attr.rs:14:7
+ |
+14 | #[structopt]
+ | ^^^^^^^^^
diff --git a/structopt/tests/ui/structopt_name_value_attr.rs b/structopt/tests/ui/structopt_name_value_attr.rs
new file mode 100644
index 0000000..3d9388f
--- /dev/null
+++ b/structopt/tests/ui/structopt_name_value_attr.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+ #[structopt = "short"]
+ debug: bool,
+}
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
+
diff --git a/structopt/tests/ui/structopt_name_value_attr.stderr b/structopt/tests/ui/structopt_name_value_attr.stderr
new file mode 100644
index 0000000..f681978
--- /dev/null
+++ b/structopt/tests/ui/structopt_name_value_attr.stderr
@@ -0,0 +1,5 @@
+error: expected parentheses
+ --> $DIR/structopt_name_value_attr.rs:14:17
+ |
+14 | #[structopt = "short"]
+ | ^
diff --git a/structopt/tests/ui/subcommand_and_flatten.rs b/structopt/tests/ui/subcommand_and_flatten.rs
new file mode 100644
index 0000000..742ee6d
--- /dev/null
+++ b/structopt/tests/ui/subcommand_and_flatten.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+ #[structopt(short)]
+ s: String,
+
+ #[structopt(subcommand, flatten)]
+ cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+ #[structopt(name = "pound")]
+ /// Pound acorns into flour for cookie dough.
+ Pound { acorns: u32 },
+
+ Sparkle {
+ #[structopt(short)]
+ color: String,
+ },
+}
+
+fn main() {
+ let opt = MakeCookie::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/subcommand_and_flatten.stderr b/structopt/tests/ui/subcommand_and_flatten.stderr
new file mode 100644
index 0000000..cacea5e
--- /dev/null
+++ b/structopt/tests/ui/subcommand_and_flatten.stderr
@@ -0,0 +1,5 @@
+error: subcommand, flatten and skip cannot be used together
+ --> $DIR/subcommand_and_flatten.rs:17:29
+ |
+17 | #[structopt(subcommand, flatten)]
+ | ^^^^^^^
diff --git a/structopt/tests/ui/subcommand_and_methods.rs b/structopt/tests/ui/subcommand_and_methods.rs
new file mode 100644
index 0000000..890f10c
--- /dev/null
+++ b/structopt/tests/ui/subcommand_and_methods.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+ #[structopt(short)]
+ s: String,
+
+ #[structopt(subcommand, long)]
+ cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+ #[structopt(name = "pound")]
+ /// Pound acorns into flour for cookie dough.
+ Pound { acorns: u32 },
+
+ Sparkle {
+ #[structopt(short)]
+ color: String,
+ },
+}
+
+fn main() {
+ let opt = MakeCookie::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/subcommand_and_methods.stderr b/structopt/tests/ui/subcommand_and_methods.stderr
new file mode 100644
index 0000000..ccaf28d
--- /dev/null
+++ b/structopt/tests/ui/subcommand_and_methods.stderr
@@ -0,0 +1,5 @@
+error: methods in attributes are not allowed for subcommand
+ --> $DIR/subcommand_and_methods.rs:17:17
+ |
+17 | #[structopt(subcommand, long)]
+ | ^^^^^^^^^^
diff --git a/structopt/tests/ui/subcommand_and_parse.rs b/structopt/tests/ui/subcommand_and_parse.rs
new file mode 100644
index 0000000..f24e4bc
--- /dev/null
+++ b/structopt/tests/ui/subcommand_and_parse.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+ #[structopt(short)]
+ s: String,
+
+ #[structopt(subcommand, parse(from_occurrences))]
+ cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+ #[structopt(name = "pound")]
+ /// Pound acorns into flour for cookie dough.
+ Pound { acorns: u32 },
+
+ Sparkle {
+ #[structopt(short)]
+ color: String,
+ },
+}
+
+fn main() {
+ let opt = MakeCookie::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/subcommand_and_parse.stderr b/structopt/tests/ui/subcommand_and_parse.stderr
new file mode 100644
index 0000000..4070056
--- /dev/null
+++ b/structopt/tests/ui/subcommand_and_parse.stderr
@@ -0,0 +1,5 @@
+error: parse attribute is not allowed for subcommand
+ --> $DIR/subcommand_and_parse.rs:17:29
+ |
+17 | #[structopt(subcommand, parse(from_occurrences))]
+ | ^^^^^
diff --git a/structopt/tests/ui/subcommand_opt_opt.rs b/structopt/tests/ui/subcommand_opt_opt.rs
new file mode 100644
index 0000000..1dd84e5
--- /dev/null
+++ b/structopt/tests/ui/subcommand_opt_opt.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+ #[structopt(short)]
+ s: String,
+
+ #[structopt(subcommand)]
+ cmd: Option<Option<Command>>,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+ #[structopt(name = "pound")]
+ /// Pound acorns into flour for cookie dough.
+ Pound { acorns: u32 },
+
+ Sparkle {
+ #[structopt(short)]
+ color: String,
+ },
+}
+
+fn main() {
+ let opt = MakeCookie::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/subcommand_opt_opt.stderr b/structopt/tests/ui/subcommand_opt_opt.stderr
new file mode 100644
index 0000000..daad02f
--- /dev/null
+++ b/structopt/tests/ui/subcommand_opt_opt.stderr
@@ -0,0 +1,5 @@
+error: Option<Option<T>> type is not allowed for subcommand
+ --> $DIR/subcommand_opt_opt.rs:18:10
+ |
+18 | cmd: Option<Option<Command>>,
+ | ^^^^^^
diff --git a/structopt/tests/ui/subcommand_opt_vec.rs b/structopt/tests/ui/subcommand_opt_vec.rs
new file mode 100644
index 0000000..17bffbf
--- /dev/null
+++ b/structopt/tests/ui/subcommand_opt_vec.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+ #[structopt(short)]
+ s: String,
+
+ #[structopt(subcommand)]
+ cmd: Option<Vec<Command>>,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+ #[structopt(name = "pound")]
+ /// Pound acorns into flour for cookie dough.
+ Pound { acorns: u32 },
+
+ Sparkle {
+ #[structopt(short)]
+ color: String,
+ },
+}
+
+fn main() {
+ let opt = MakeCookie::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/subcommand_opt_vec.stderr b/structopt/tests/ui/subcommand_opt_vec.stderr
new file mode 100644
index 0000000..a9833a6
--- /dev/null
+++ b/structopt/tests/ui/subcommand_opt_vec.stderr
@@ -0,0 +1,5 @@
+error: Option<Vec<T>> type is not allowed for subcommand
+ --> $DIR/subcommand_opt_vec.rs:18:10
+ |
+18 | cmd: Option<Vec<Command>>,
+ | ^^^^^^
diff --git a/structopt/tests/ui/tuple_struct.rs b/structopt/tests/ui/tuple_struct.rs
new file mode 100644
index 0000000..af9b1d5
--- /dev/null
+++ b/structopt/tests/ui/tuple_struct.rs
@@ -0,0 +1,18 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt(u32);
+
+fn main() {
+ let opt = Opt::from_args();
+ println!("{:?}", opt);
+}
diff --git a/structopt/tests/ui/tuple_struct.stderr b/structopt/tests/ui/tuple_struct.stderr
new file mode 100644
index 0000000..9f2876f
--- /dev/null
+++ b/structopt/tests/ui/tuple_struct.stderr
@@ -0,0 +1,5 @@
+error: structopt only supports non-tuple structs and enums
+ --> $DIR/tuple_struct.rs:11:10
+ |
+11 | #[derive(StructOpt, Debug)]
+ | ^^^^^^^^^
diff --git a/structopt/tests/utils.rs b/structopt/tests/utils.rs
new file mode 100644
index 0000000..c0684a2
--- /dev/null
+++ b/structopt/tests/utils.rs
@@ -0,0 +1,45 @@
+#![allow(unused)]
+
+use structopt::StructOpt;
+
+pub fn get_help<T: StructOpt>() -> String {
+ let mut output = Vec::new();
+ <T as StructOpt>::clap().write_help(&mut output).unwrap();
+ let output = String::from_utf8(output).unwrap();
+
+ eprintln!("\n%%% HELP %%%:=====\n{}\n=====\n", output);
+ eprintln!("\n%%% HELP (DEBUG) %%%:=====\n{:?}\n=====\n", output);
+
+ output
+}
+
+pub fn get_long_help<T: StructOpt>() -> String {
+ let mut output = Vec::new();
+ <T as StructOpt>::clap()
+ .write_long_help(&mut output)
+ .unwrap();
+ let output = String::from_utf8(output).unwrap();
+
+ eprintln!("\n%%% LONG_HELP %%%:=====\n{}\n=====\n", output);
+ eprintln!("\n%%% LONG_HELP (DEBUG) %%%:=====\n{:?}\n=====\n", output);
+
+ output
+}
+
+pub fn get_subcommand_long_help<T: StructOpt>(subcmd: &str) -> String {
+ let output = <T as StructOpt>::clap()
+ .get_matches_from_safe(vec!["test", subcmd, "--help"])
+ .expect_err("")
+ .message;
+
+ eprintln!(
+ "\n%%% SUBCOMMAND `{}` HELP %%%:=====\n{}\n=====\n",
+ subcmd, output
+ );
+ eprintln!(
+ "\n%%% SUBCOMMAND `{}` HELP (DEBUG) %%%:=====\n{:?}\n=====\n",
+ subcmd, output
+ );
+
+ output
+}
diff --git a/syn-mid/.editorconfig b/syn-mid/.editorconfig
new file mode 100644
index 0000000..920ea40
--- /dev/null
+++ b/syn-mid/.editorconfig
@@ -0,0 +1,22 @@
+# EditorConfig configuration
+# http://EditorConfig.org
+
+# Top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file, utf-8 charset
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+
+# Match rust/toml, set 4 space indentation
+[*.{rs,toml}]
+indent_style = space
+indent_size = 4
+
+# Match yaml/markdown, set 2 space indentation
+[*.{yml,md}]
+indent_style = space
+indent_size = 2
diff --git a/syn-mid/.gitignore b/syn-mid/.gitignore
new file mode 100644
index 0000000..2e6c307
--- /dev/null
+++ b/syn-mid/.gitignore
@@ -0,0 +1,6 @@
+.idea/
+.vscode/
+target/
+**/*.rs.bk
+Cargo.lock
+___*
diff --git a/syn-mid/.rustfmt.toml b/syn-mid/.rustfmt.toml
new file mode 100644
index 0000000..a27c0b7
--- /dev/null
+++ b/syn-mid/.rustfmt.toml
@@ -0,0 +1,4 @@
+# Set the default settings again to always apply the proper formatting without being affected by the editor settings.
+# https://github.com/rust-lang/rls/issues/501#issuecomment-333717736
+edition = "2018"
+tab_spaces = 4
diff --git a/syn-mid/CHANGELOG.md b/syn-mid/CHANGELOG.md
new file mode 100644
index 0000000..25c17c1
--- /dev/null
+++ b/syn-mid/CHANGELOG.md
@@ -0,0 +1,33 @@
+# Unreleased
+
+# 0.4.0 - 2019-08-15
+
+* Updated all data structures based on `syn` 1.0.
+
+* Updated `proc-macro2`, `syn`, and `quote` to 1.0.
+
+* Bumped the minimum required version from Rust 1.30 to Rust 1.31.
+
+# 0.3.0 - 2019-02-18
+
+* Removed support for unneeded syntax.
+
+* Removed unneeded types and fields.
+
+* Implemented `Parse` for `Block`.
+
+* Changed `clone-impls` feature to "disabled by default".
+
+* Removed `extra-traits` feature.
+
+* Bumped the minimum required version from Rust 1.15 to Rust 1.30.
+
+# 0.2.0 - 2019-02-15
+
+* Reduced features.
+
+* Fixed bugs.
+
+# 0.1.0 - 2019-02-14
+
+Initial release
diff --git a/syn-mid/Cargo.toml b/syn-mid/Cargo.toml
new file mode 100644
index 0000000..f92e7a0
--- /dev/null
+++ b/syn-mid/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "syn-mid"
+version = "0.4.0"
+authors = ["Taiki Endo <te316e89@gmail.com>"]
+edition = "2018"
+license = "Apache-2.0/MIT"
+repository = "https://github.com/taiki-e/syn-mid"
+documentation = "https://docs.rs/syn-mid/"
+readme = "README.md"
+keywords = ["syn", "macros"]
+categories = ["development-tools::procedural-macro-helpers"]
+description = "Providing the features between \"full\" and \"derive\" of syn."
+
+[workspace]
+members = ["examples/const_fn", "examples/const_fn_test"]
+
+[features]
+clone-impls = ["syn/clone-impls"]
+
+[dependencies]
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "1.0", default-features = false, features = ["parsing", "printing", "derive"] }
diff --git a/syn-mid/LICENSE-APACHE b/syn-mid/LICENSE-APACHE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/syn-mid/LICENSE-APACHE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/syn-mid/LICENSE-MIT b/syn-mid/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/syn-mid/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/syn-mid/README.md b/syn-mid/README.md
new file mode 100644
index 0000000..b9b1c75
--- /dev/null
+++ b/syn-mid/README.md
@@ -0,0 +1,72 @@
+# syn-mid
+
+[![Build Status][azure-badge]][azure-url]
+[![Crates.io][crates-version-badge]][crates-url]
+[![Docs.rs][docs-badge]][docs-url]
+[![License][crates-license-badge]][crates-url]
+[![Minimum supported Rust version][rustc-badge]][rustc-url]
+
+[azure-badge]: https://dev.azure.com/taiki-e/taiki-e/_apis/build/status/taiki-e.syn-mid?branchName=master
+[azure-url]: https://dev.azure.com/taiki-e/taiki-e/_build/latest?definitionId=11&branchName=master
+[crates-version-badge]: https://img.shields.io/crates/v/syn-mid.svg
+[crates-license-badge]: https://img.shields.io/crates/l/syn-mid.svg
+[crates-badge]: https://img.shields.io/crates/v/syn-mid.svg
+[crates-url]: https://crates.io/crates/syn-mid/
+[docs-badge]: https://docs.rs/syn-mid/badge.svg
+[docs-url]: https://docs.rs/syn-mid/
+[rustc-badge]: https://img.shields.io/badge/rustc-1.31+-lightgray.svg
+[rustc-url]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html
+
+Providing the features between "full" and "derive" of syn.
+
+This crate provides the following two unique data structures.
+
+* `syn_mid::ItemFn` -- A function whose body is not parsed.
+
+ ```text
+ fn process(n: usize) -> Result<()> { ... }
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^
+ ```
+
+* `syn_mid::Block` -- A block whose body is not parsed.
+
+ ```text
+ { ... }
+ ^ ^
+ ```
+
+Other data structures are the same as data structures of [syn]. These are defined in this crate because they cannot be used in [syn] without "full" feature.
+
+[syn]: https://github.com/dtolnay/syn
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+syn-mid = "0.4"
+```
+
+The current syn-mid requires Rust 1.31 or later.
+
+[**Examples**](examples)
+
+[**Documentation**](https://docs.rs/syn-mid/)
+
+## Optional features
+
+* **`clone-impls`** — Clone impls for all syntax tree types.
+
+## License
+
+Licensed under either of
+
+* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
+* MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
diff --git a/syn-mid/azure-pipelines.yml b/syn-mid/azure-pipelines.yml
new file mode 100644
index 0000000..6f0c968
--- /dev/null
+++ b/syn-mid/azure-pipelines.yml
@@ -0,0 +1,49 @@
+trigger:
+- master
+- staging
+- trying
+
+variables:
+ RUSTFLAGS: -Dwarnings
+
+jobs:
+# This is the minimum Rust version supported by syn-mid.
+# When updating this, the reminder to update the minimum supported
+# Rust version in README.md.
+#
+# Tests are not run as tests may require newer versions of rust.
+- template: ci/azure-test.yml
+ parameters:
+ name: minrust
+ rust: 1.31.0
+
+- template: ci/azure-test.yml
+ parameters:
+ name: stable
+ rust: stable
+
+- template: ci/azure-test.yml
+ parameters:
+ name: beta
+ rust: beta
+
+- template: ci/azure-test.yml
+ parameters:
+ name: nightly
+ rust: nightly
+ cmd: test
+
+- template: ci/azure-clippy.yml
+ parameters:
+ name: clippy
+ rust: nightly
+
+- template: ci/azure-rustfmt.yml
+ parameters:
+ name: rustfmt
+ rust: stable
+
+- template: ci/azure-rustdoc.yml
+ parameters:
+ name: rustdoc
+ rust: nightly
diff --git a/syn-mid/bors.toml b/syn-mid/bors.toml
new file mode 100644
index 0000000..b477894
--- /dev/null
+++ b/syn-mid/bors.toml
@@ -0,0 +1 @@
+status = ["taiki-e.syn-mid"]
diff --git a/syn-mid/ci/azure-clippy.yml b/syn-mid/ci/azure-clippy.yml
new file mode 100644
index 0000000..22165c6
--- /dev/null
+++ b/syn-mid/ci/azure-clippy.yml
@@ -0,0 +1,31 @@
+jobs:
+- job: ${{ parameters.name }}
+ displayName: Clippy
+ pool:
+ vmImage: ubuntu-16.04
+
+ steps:
+ - template: azure-install-rust.yml
+ parameters:
+ rust: ${{ parameters.rust }}
+
+ - script: |
+ set +e
+ if rustup component add clippy; then
+ set -e
+ else
+ set -e
+ target=`curl https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy`
+ echo "'clippy' is unavailable on the toolchain '${{ parameters.rust }}', use the toolchain 'nightly-$target' instead"
+ rustup toolchain install nightly-$target
+ rustup default nightly-$target
+ rustup component add clippy
+ rustup toolchain list
+ rustc -Vv
+ cargo -V
+ fi
+ cargo clippy --version
+ displayName: rustup component add clippy
+
+ - script: cargo clippy --all --all-features
+ displayName: cargo clippy --all-features
diff --git a/syn-mid/ci/azure-install-rust.yml b/syn-mid/ci/azure-install-rust.yml
new file mode 100644
index 0000000..6b008c6
--- /dev/null
+++ b/syn-mid/ci/azure-install-rust.yml
@@ -0,0 +1,33 @@
+steps:
+ # Linux and macOS.
+ - script: |
+ set -e
+ curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none
+ export PATH=$PATH:$HOME/.cargo/bin
+ rustup toolchain install $RUSTUP_TOOLCHAIN
+ rustup default $RUSTUP_TOOLCHAIN
+ echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin"
+ env:
+ RUSTUP_TOOLCHAIN: ${{ parameters.rust }}
+ displayName: Install rust (*nix)
+ condition: not(eq(variables['Agent.OS'], 'Windows_NT'))
+
+ # Windows.
+ - script: |
+ curl -sSf -o rustup-init.exe https://win.rustup.rs
+ rustup-init.exe -y --default-toolchain none
+ set PATH=%PATH%;%USERPROFILE%\.cargo\bin
+ rustup toolchain install %RUSTUP_TOOLCHAIN%
+ rustup default %RUSTUP_TOOLCHAIN%
+ echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin"
+ env:
+ RUSTUP_TOOLCHAIN: ${{ parameters.rust }}
+ displayName: Install rust (windows)
+ condition: eq(variables['Agent.OS'], 'Windows_NT')
+
+ # All platforms.
+ - script: |
+ rustup toolchain list
+ rustc -Vv
+ cargo -V
+ displayName: Query rust and cargo versions
diff --git a/syn-mid/ci/azure-rustdoc.yml b/syn-mid/ci/azure-rustdoc.yml
new file mode 100644
index 0000000..99a43ff
--- /dev/null
+++ b/syn-mid/ci/azure-rustdoc.yml
@@ -0,0 +1,13 @@
+jobs:
+- job: ${{ parameters.name }}
+ displayName: Rustdoc
+ pool:
+ vmImage: ubuntu-16.04
+
+ steps:
+ - template: azure-install-rust.yml
+ parameters:
+ rust: ${{ parameters.rust }}
+
+ - script: RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all --all-features
+ displayName: cargo doc --all-features
diff --git a/syn-mid/ci/azure-rustfmt.yml b/syn-mid/ci/azure-rustfmt.yml
new file mode 100644
index 0000000..0b20da3
--- /dev/null
+++ b/syn-mid/ci/azure-rustfmt.yml
@@ -0,0 +1,18 @@
+jobs:
+- job: ${{ parameters.name }}
+ displayName: Rustfmt
+ pool:
+ vmImage: ubuntu-16.04
+
+ steps:
+ - template: azure-install-rust.yml
+ parameters:
+ rust: ${{ parameters.rust }}
+
+ - script: |
+ rustup component add rustfmt
+ cargo fmt --version
+ displayName: rustup component add rustfmt
+
+ - script: cargo fmt --all -- --check
+ displayName: cargo fmt -- --check
diff --git a/syn-mid/ci/azure-test.yml b/syn-mid/ci/azure-test.yml
new file mode 100644
index 0000000..32a56ed
--- /dev/null
+++ b/syn-mid/ci/azure-test.yml
@@ -0,0 +1,34 @@
+parameters:
+ cmd: check
+
+jobs:
+- job: ${{ parameters.name }}
+ displayName: ${{ parameters.displayName }} ${{ parameters.rust }}
+ strategy:
+ matrix:
+ Linux:
+ vmImage: ubuntu-16.04
+
+ ${{ if parameters.cross }}:
+ MacOS:
+ vmImage: macOS-10.13
+ Windows:
+ vmImage: vs2017-win2016
+ pool:
+ vmImage: $(vmImage)
+
+ steps:
+ - template: azure-install-rust.yml
+ parameters:
+ rust: ${{ parameters.rust }}
+
+ - script: |
+ cargo ${{ parameters.cmd }}
+ cargo ${{ parameters.cmd }} --all-features
+ displayName: cargo ${{ parameters.cmd }}
+
+ - ${{ if eq(parameters.rust, 'nightly') }}:
+ - script: |
+ cargo update -Zminimal-versions
+ cargo check --all-features
+ displayName: cargo check -Zminimal-versions
diff --git a/syn-mid/examples/const_fn/Cargo.toml b/syn-mid/examples/const_fn/Cargo.toml
new file mode 100644
index 0000000..d823e76
--- /dev/null
+++ b/syn-mid/examples/const_fn/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "const_fn"
+version = "0.0.0"
+authors = ["Taiki Endo <te316e89@gmail.com>"]
+edition = "2018"
+publish = false
+
+[lib]
+proc-macro = true
+path = "lib.rs"
+
+[dependencies]
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = "1.0"
+syn-mid = { version = "0.4", path = "../..", features = ["clone-impls"] }
diff --git a/syn-mid/examples/const_fn/lib.rs b/syn-mid/examples/const_fn/lib.rs
new file mode 100644
index 0000000..29255f2
--- /dev/null
+++ b/syn-mid/examples/const_fn/lib.rs
@@ -0,0 +1,31 @@
+#![warn(rust_2018_idioms)]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+use syn_mid::ItemFn;
+
+/// An attribute for easy generation of a const function with conditional compilations.
+#[proc_macro_attribute]
+pub fn const_fn(args: TokenStream, function: TokenStream) -> TokenStream {
+ assert!(!args.is_empty(), "requires an argument");
+
+ let mut function = syn::parse_macro_input!(function as ItemFn);
+ let mut const_function = function.clone();
+
+ if function.constness.is_some() {
+ function.constness = None;
+ } else {
+ const_function.constness = Some(Default::default());
+ }
+
+ let args = TokenStream2::from(args);
+ TokenStream::from(quote! {
+ #[cfg(not(#args))]
+ #function
+ #[cfg(#args)]
+ #const_function
+ })
+}
diff --git a/syn-mid/examples/const_fn_test/Cargo.toml b/syn-mid/examples/const_fn_test/Cargo.toml
new file mode 100644
index 0000000..b3e2807
--- /dev/null
+++ b/syn-mid/examples/const_fn_test/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "const_fn_test"
+version = "0.0.0"
+authors = ["Taiki Endo <te316e89@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+const_fn = { path = "../const_fn" }
diff --git a/syn-mid/examples/const_fn_test/build.rs b/syn-mid/examples/const_fn_test/build.rs
new file mode 100644
index 0000000..bebf234
--- /dev/null
+++ b/syn-mid/examples/const_fn_test/build.rs
@@ -0,0 +1,16 @@
+use std::{env, process::Command};
+
+fn main() {
+ println!("cargo:rerun-if-changed=build.rs");
+
+ if is_nightly() {
+ println!("cargo:rustc-cfg=nightly");
+ }
+}
+
+fn is_nightly() -> bool {
+ env::var_os("RUSTC")
+ .and_then(|rustc| Command::new(rustc).arg("--version").output().ok())
+ .and_then(|output| String::from_utf8(output.stdout).ok())
+ .map_or(false, |version| version.contains("nightly"))
+}
diff --git a/syn-mid/examples/const_fn_test/tests/test.rs b/syn-mid/examples/const_fn_test/tests/test.rs
new file mode 100644
index 0000000..1b2c742
--- /dev/null
+++ b/syn-mid/examples/const_fn_test/tests/test.rs
@@ -0,0 +1,25 @@
+#![cfg_attr(nightly, feature(const_fn, const_vec_new))]
+#![warn(rust_2018_idioms)]
+#![allow(dead_code)]
+
+use const_fn::const_fn;
+
+#[const_fn(nightly)]
+fn const_vec_new<T>() -> Vec<T> {
+ let vec = Vec::new();
+ vec
+}
+
+#[test]
+fn test_stable() {
+ assert_eq!(const_vec_new::<u8>(), Vec::new());
+}
+
+#[cfg(nightly)]
+const CONST_UNSTABLE: Vec<u8> = const_vec_new();
+
+#[cfg(nightly)]
+#[test]
+fn test_unstable() {
+ assert_eq!(CONST_UNSTABLE, Vec::new());
+}
diff --git a/syn-mid/src/arg.rs b/syn-mid/src/arg.rs
new file mode 100644
index 0000000..593a1ac
--- /dev/null
+++ b/syn-mid/src/arg.rs
@@ -0,0 +1,99 @@
+use syn::{Attribute, Lifetime, Token};
+
+use super::PatType;
+
+ast_enum_of_structs! {
+ /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`.
+ pub enum FnArg {
+ /// The `self` argument of an associated method, whether taken by value
+ /// or by reference.
+ Receiver(Receiver),
+
+ /// A function argument accepted by pattern and type.
+ Typed(PatType),
+ }
+}
+
+ast_struct! {
+ /// The `self` argument of an associated method, whether taken by value
+ /// or by reference.
+ pub struct Receiver {
+ pub attrs: Vec<Attribute>,
+ pub reference: Option<(Token![&], Option<Lifetime>)>,
+ pub mutability: Option<Token![mut]>,
+ pub self_token: Token![self],
+ }
+}
+
+mod parsing {
+ use syn::{
+ parse::{discouraged::Speculative, Parse, ParseStream, Result},
+ Attribute, Token,
+ };
+
+ use super::{FnArg, PatType, Receiver};
+
+ impl Parse for FnArg {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+
+ let ahead = input.fork();
+ if let Ok(mut receiver) = ahead.parse::<Receiver>() {
+ if !ahead.peek(Token![:]) {
+ input.advance_to(&ahead);
+ receiver.attrs = attrs;
+ return Ok(FnArg::Receiver(receiver));
+ }
+ }
+
+ let mut typed = input.call(fn_arg_typed)?;
+ typed.attrs = attrs;
+ Ok(FnArg::Typed(typed))
+ }
+ }
+
+ impl Parse for Receiver {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ Ok(Self {
+ attrs: Vec::new(),
+ reference: {
+ if input.peek(Token![&]) {
+ Some((input.parse()?, input.parse()?))
+ } else {
+ None
+ }
+ },
+ mutability: input.parse()?,
+ self_token: input.parse()?,
+ })
+ }
+ }
+
+ fn fn_arg_typed(input: ParseStream<'_>) -> Result<PatType> {
+ Ok(PatType {
+ attrs: Vec::new(),
+ pat: input.parse()?,
+ colon_token: input.parse()?,
+ ty: Box::new(input.parse()?),
+ })
+ }
+}
+
+mod printing {
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ use super::Receiver;
+
+ impl ToTokens for Receiver {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ if let Some((ampersand, lifetime)) = &self.reference {
+ ampersand.to_tokens(tokens);
+ lifetime.to_tokens(tokens);
+ }
+ self.mutability.to_tokens(tokens);
+ self.self_token.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn-mid/src/lib.rs b/syn-mid/src/lib.rs
new file mode 100644
index 0000000..69bdec9
--- /dev/null
+++ b/syn-mid/src/lib.rs
@@ -0,0 +1,190 @@
+//! Providing the features between "full" and "derive" of syn.
+//!
+//! This crate provides the following two unique data structures.
+//!
+//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
+//!
+//! ```text
+//! fn process(n: usize) -> Result<()> { ... }
+//! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^
+//! ```
+//!
+//! * [`syn_mid::Block`] -- A block whose body is not parsed.
+//!
+//! ```text
+//! { ... }
+//! ^ ^
+//! ```
+//!
+//! Other data structures are the same as data structures of [syn]. These are defined in this crate
+//! because they cannot be used in [syn] without "full" feature.
+//!
+//! ## Optional features
+//!
+//! syn-mid in the default features aims to provide the features between "full"
+//! and "derive" of [syn].
+//!
+//! * **`clone-impls`** — Clone impls for all syntax tree types.
+//!
+//! [`syn_mid::ItemFn`]: struct.ItemFn.html
+//! [`syn_mid::Block`]: struct.Block.html
+//! [syn]: https://github.com/dtolnay/syn
+//!
+
+#![doc(html_root_url = "https://docs.rs/syn-mid/0.4.0")]
+#![doc(test(attr(deny(warnings), allow(dead_code, unused_assignments, unused_variables))))]
+#![warn(unsafe_code)]
+#![warn(rust_2018_idioms, unreachable_pub)]
+#![warn(single_use_lifetimes)]
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(
+ clippy::eval_order_dependence,
+ clippy::large_enum_variant,
+ clippy::module_name_repetitions,
+ clippy::use_self
+)]
+
+// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.
+
+#[macro_use]
+mod macros;
+
+mod arg;
+mod pat;
+mod path;
+
+pub use self::arg::*;
+pub use self::pat::*;
+
+use proc_macro2::TokenStream;
+use syn::{
+ punctuated::Punctuated, token, Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility,
+};
+
+ast_struct! {
+ /// A braced block containing Rust statements.
+ pub struct Block {
+ pub brace_token: token::Brace,
+ /// Statements in a block
+ pub stmts: TokenStream,
+ }
+}
+
+ast_struct! {
+ /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
+ /// }`.
+ pub struct ItemFn {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub constness: Option<Token![const]>,
+ pub asyncness: Option<Token![async]>,
+ pub unsafety: Option<Token![unsafe]>,
+ pub abi: Option<Abi>,
+ pub fn_token: Token![fn],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub paren_token: token::Paren,
+ pub inputs: Punctuated<FnArg, Token![,]>,
+ pub output: ReturnType,
+ pub block: Block,
+ }
+}
+
+mod parsing {
+ use syn::{
+ braced, parenthesized,
+ parse::{Parse, ParseStream, Result},
+ Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility, WhereClause,
+ };
+
+ use super::{Block, FnArg, ItemFn};
+
+ impl Parse for Block {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let content;
+ Ok(Self {
+ brace_token: braced!(content in input),
+ stmts: content.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ItemFn {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let constness: Option<Token![const]> = input.parse()?;
+ let asyncness: Option<Token![async]> = input.parse()?;
+ let unsafety: Option<Token![unsafe]> = input.parse()?;
+ let abi: Option<Abi> = input.parse()?;
+ let fn_token: Token![fn] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let generics: Generics = input.parse()?;
+
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let inputs = content.parse_terminated(FnArg::parse)?;
+
+ let output: ReturnType = input.parse()?;
+ let where_clause: Option<WhereClause> = input.parse()?;
+
+ let block = input.parse()?;
+
+ Ok(Self {
+ attrs,
+ vis,
+ constness,
+ asyncness,
+ unsafety,
+ abi,
+ fn_token,
+ ident,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ paren_token,
+ inputs,
+ output,
+ block,
+ })
+ }
+ }
+}
+
+mod printing {
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ use super::{Block, ItemFn};
+
+ impl ToTokens for Block {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.stmts.clone());
+ });
+ }
+ }
+
+ impl ToTokens for ItemFn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.vis.to_tokens(tokens);
+ self.constness.to_tokens(tokens);
+ self.asyncness.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.abi.to_tokens(tokens);
+ self.fn_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.inputs.to_tokens(tokens);
+ });
+ self.output.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.block.stmts.clone());
+ });
+ }
+ }
+}
diff --git a/syn-mid/src/macros.rs b/syn-mid/src/macros.rs
new file mode 100644
index 0000000..87be7b4
--- /dev/null
+++ b/syn-mid/src/macros.rs
@@ -0,0 +1,107 @@
+macro_rules! ast_struct {
+ (
+ [$($attrs_pub:tt)*]
+ struct $name:ident $($rest:tt)*
+ ) => {
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* struct $name $($rest)*
+ };
+
+ ($($t:tt)*) => {
+ strip_attrs_pub!(ast_struct!($($t)*));
+ };
+}
+
+macro_rules! ast_enum {
+ (
+ [$($attrs_pub:tt)*]
+ enum $name:ident $($rest:tt)*
+ ) => (
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* enum $name $($rest)*
+ );
+
+ ($($t:tt)*) => {
+ strip_attrs_pub!(ast_enum!($($t)*));
+ };
+}
+
+macro_rules! ast_enum_of_structs {
+ (
+ $(#[$enum_attr:meta])*
+ $pub:ident $enum:ident $name:ident $body:tt
+ ) => {
+ ast_enum!($(#[$enum_attr])* $pub $enum $name $body);
+ ast_enum_of_structs_impl!($pub $enum $name $body);
+ };
+}
+
+macro_rules! ast_enum_of_structs_impl {
+ (
+ $pub:ident $enum:ident $name:ident {
+ $(
+ $(#[$variant_attr:meta])*
+ $variant:ident $( ($member:ident) )*,
+ )*
+ }
+ ) => {
+ check_keyword_matches!(pub $pub);
+ check_keyword_matches!(enum $enum);
+
+ $(
+ $(
+ impl From<$member> for $name {
+ fn from(e: $member) -> $name {
+ $name::$variant(e)
+ }
+ }
+ )*
+ )*
+
+ generate_to_tokens! {
+ ()
+ tokens
+ $name { $($variant $($member)*,)* }
+ }
+ };
+}
+
+macro_rules! generate_to_tokens {
+ (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident, $($next:tt)*}) => {
+ generate_to_tokens!(
+ ($($arms)* $name::$variant => {})
+ $tokens $name { $($next)* }
+ );
+ };
+
+ (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident $member:ident, $($next:tt)*}) => {
+ generate_to_tokens!(
+ ($($arms)* $name::$variant(_e) => quote::ToTokens::to_tokens(_e, $tokens),)
+ $tokens $name { $($next)* }
+ );
+ };
+
+ (($($arms:tt)*) $tokens:ident $name:ident {}) => {
+ impl quote::ToTokens for $name {
+ fn to_tokens(&self, $tokens: &mut proc_macro2::TokenStream) {
+ match self {
+ $($arms)*
+ }
+ }
+ }
+ };
+}
+
+macro_rules! strip_attrs_pub {
+ ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
+ check_keyword_matches!(pub $pub);
+
+ $mac!([$(#[$m])* $pub] $($t)*);
+ };
+}
+
+macro_rules! check_keyword_matches {
+ (struct struct) => {};
+ (enum enum) => {};
+ (pub pub) => {};
+}
diff --git a/syn-mid/src/pat.rs b/syn-mid/src/pat.rs
new file mode 100644
index 0000000..8f95381
--- /dev/null
+++ b/syn-mid/src/pat.rs
@@ -0,0 +1,413 @@
+use syn::{punctuated::Punctuated, token, Attribute, Ident, Member, Path, Token, Type};
+
+ast_enum_of_structs! {
+ /// A pattern in a local binding, function signature, match expression, or
+ /// various other places.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum Pat {
+ /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
+ Ident(PatIdent),
+
+ /// A path pattern like `Color::Red`.
+ Path(PatPath),
+
+ /// A reference pattern: `&mut var`.
+ Reference(PatReference),
+
+ /// A struct or struct variant pattern: `Variant { x, y, .. }`.
+ Struct(PatStruct),
+
+ /// A tuple pattern: `(a, b)`.
+ Tuple(PatTuple),
+
+ /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
+ TupleStruct(PatTupleStruct),
+
+ /// A type ascription pattern: `foo: f64`.
+ Type(PatType),
+
+ /// A pattern that matches any value: `_`.
+ Wild(PatWild),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
+ pub struct PatIdent {
+ pub attrs: Vec<Attribute>,
+ pub by_ref: Option<Token![ref]>,
+ pub mutability: Option<Token![mut]>,
+ pub ident: Ident,
+ }
+}
+
+ast_struct! {
+ /// A path pattern like `Color::Red`.
+ pub struct PatPath {
+ pub attrs: Vec<Attribute>,
+ pub path: Path,
+ }
+}
+
+ast_struct! {
+ /// A reference pattern: `&mut var`.
+ pub struct PatReference {
+ pub attrs: Vec<Attribute>,
+ pub and_token: Token![&],
+ pub mutability: Option<Token![mut]>,
+ pub pat: Box<Pat>,
+ }
+}
+
+ast_struct! {
+ /// A struct or struct variant pattern: `Variant { x, y, .. }`.
+ pub struct PatStruct {
+ pub attrs: Vec<Attribute>,
+ pub path: Path,
+ pub brace_token: token::Brace,
+ pub fields: Punctuated<FieldPat, Token![,]>,
+ pub dot2_token: Option<Token![..]>,
+ }
+}
+
+ast_struct! {
+ /// A tuple pattern: `(a, b)`.
+ pub struct PatTuple {
+ pub attrs: Vec<Attribute>,
+ pub paren_token: token::Paren,
+ pub elems: Punctuated<Pat, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
+ pub struct PatTupleStruct {
+ pub attrs: Vec<Attribute>,
+ pub path: Path,
+ pub pat: PatTuple,
+ }
+}
+
+ast_struct! {
+ /// A type ascription pattern: `foo: f64`.
+ pub struct PatType {
+ pub attrs: Vec<Attribute>,
+ pub pat: Box<Pat>,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A pattern that matches any value: `_`.
+ pub struct PatWild {
+ pub attrs: Vec<Attribute>,
+ pub underscore_token: Token![_],
+ }
+}
+
+ast_struct! {
+ /// A single field in a struct pattern.
+ ///
+ /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
+ /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
+ pub struct FieldPat {
+ pub attrs: Vec<Attribute>,
+ pub member: Member,
+ pub colon_token: Option<Token![:]>,
+ pub pat: Box<Pat>,
+ }
+}
+
+mod parsing {
+ use syn::{
+ braced,
+ ext::IdentExt,
+ parenthesized,
+ parse::{Parse, ParseStream, Result},
+ punctuated::Punctuated,
+ token, Ident, Member, Path, Token,
+ };
+
+ use crate::path;
+
+ use super::{
+ FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
+ PatWild,
+ };
+
+ impl Parse for Pat {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Ident)
+ && ({
+ input.peek2(Token![::])
+ || input.peek2(token::Brace)
+ || input.peek2(token::Paren)
+ })
+ || input.peek(Token![self]) && input.peek2(Token![::])
+ || lookahead.peek(Token![::])
+ || lookahead.peek(Token![<])
+ || input.peek(Token![Self])
+ || input.peek(Token![super])
+ || input.peek(Token![extern])
+ || input.peek(Token![crate])
+ {
+ pat_path_or_struct(input)
+ } else if lookahead.peek(Token![_]) {
+ input.call(pat_wild).map(Pat::Wild)
+ } else if lookahead.peek(Token![ref])
+ || lookahead.peek(Token![mut])
+ || input.peek(Token![self])
+ || input.peek(Ident)
+ {
+ input.call(pat_ident).map(Pat::Ident)
+ } else if lookahead.peek(Token![&]) {
+ input.call(pat_reference).map(Pat::Reference)
+ } else if lookahead.peek(token::Paren) {
+ input.call(pat_tuple).map(Pat::Tuple)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ fn pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat> {
+ let path = path::parse_path(input)?;
+
+ if input.peek(token::Brace) {
+ pat_struct(input, path).map(Pat::Struct)
+ } else if input.peek(token::Paren) {
+ pat_tuple_struct(input, path).map(Pat::TupleStruct)
+ } else {
+ Ok(Pat::Path(PatPath {
+ attrs: Vec::new(),
+ path,
+ }))
+ }
+ }
+
+ fn pat_wild(input: ParseStream<'_>) -> Result<PatWild> {
+ Ok(PatWild {
+ attrs: Vec::new(),
+ underscore_token: input.parse()?,
+ })
+ }
+
+ fn pat_ident(input: ParseStream<'_>) -> Result<PatIdent> {
+ Ok(PatIdent {
+ attrs: Vec::new(),
+ by_ref: input.parse()?,
+ mutability: input.parse()?,
+ ident: input.call(Ident::parse_any)?,
+ })
+ }
+
+ fn pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct> {
+ Ok(PatTupleStruct {
+ attrs: Vec::new(),
+ path,
+ pat: input.call(pat_tuple)?,
+ })
+ }
+
+ fn pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct> {
+ let content;
+ let brace_token = braced!(content in input);
+
+ let mut fields = Punctuated::new();
+ while !content.is_empty() && !content.peek(Token![..]) {
+ let value = content.call(field_pat)?;
+ fields.push_value(value);
+ if !content.peek(Token![,]) {
+ break;
+ }
+ let punct: Token![,] = content.parse()?;
+ fields.push_punct(punct);
+ }
+
+ let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) {
+ Some(content.parse()?)
+ } else {
+ None
+ };
+
+ Ok(PatStruct {
+ attrs: Vec::new(),
+ path,
+ brace_token,
+ fields,
+ dot2_token,
+ })
+ }
+
+ fn field_pat(input: ParseStream<'_>) -> Result<FieldPat> {
+ let boxed: Option<Token![box]> = input.parse()?;
+ let by_ref: Option<Token![ref]> = input.parse()?;
+ let mutability: Option<Token![mut]> = input.parse()?;
+ let member: Member = input.parse()?;
+
+ if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
+ || is_unnamed(&member)
+ {
+ return Ok(FieldPat {
+ attrs: Vec::new(),
+ member,
+ colon_token: input.parse()?,
+ pat: input.parse()?,
+ });
+ }
+
+ let ident = match member {
+ Member::Named(ident) => ident,
+ Member::Unnamed(_) => unreachable!(),
+ };
+
+ let pat = Pat::Ident(PatIdent {
+ attrs: Vec::new(),
+ by_ref,
+ mutability,
+ ident: ident.clone(),
+ });
+
+ Ok(FieldPat {
+ member: Member::Named(ident),
+ pat: Box::new(pat),
+ attrs: Vec::new(),
+ colon_token: None,
+ })
+ }
+
+ fn pat_tuple(input: ParseStream<'_>) -> Result<PatTuple> {
+ let content;
+ let paren_token = parenthesized!(content in input);
+
+ let mut elems = Punctuated::new();
+ while !content.is_empty() {
+ let value: Pat = content.parse()?;
+ elems.push_value(value);
+ if content.is_empty() {
+ break;
+ }
+ let punct = content.parse()?;
+ elems.push_punct(punct);
+ }
+
+ Ok(PatTuple {
+ attrs: Vec::new(),
+ paren_token,
+ elems,
+ })
+ }
+
+ fn pat_reference(input: ParseStream<'_>) -> Result<PatReference> {
+ Ok(PatReference {
+ attrs: Vec::new(),
+ and_token: input.parse()?,
+ mutability: input.parse()?,
+ pat: input.parse()?,
+ })
+ }
+
+ fn is_unnamed(member: &Member) -> bool {
+ match member {
+ Member::Named(_) => false,
+ Member::Unnamed(_) => true,
+ }
+ }
+}
+
+mod printing {
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+ use syn::Token;
+
+ use super::{
+ FieldPat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct, PatType,
+ PatWild,
+ };
+
+ impl ToTokens for PatWild {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.underscore_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatIdent {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.by_ref.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ self.fields.to_tokens(tokens);
+ // NOTE: We need a comma before the dot2 token if it is present.
+ if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ self.dot2_token.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for PatTupleStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.pat.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatPath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens)
+ }
+ }
+
+ impl ToTokens for PatTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.elems.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for PatReference {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.and_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for FieldPat {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if let Some(colon_token) = &self.colon_token {
+ self.member.to_tokens(tokens);
+ colon_token.to_tokens(tokens);
+ }
+ self.pat.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn-mid/src/path.rs b/syn-mid/src/path.rs
new file mode 100644
index 0000000..8093b53
--- /dev/null
+++ b/syn-mid/src/path.rs
@@ -0,0 +1,50 @@
+use syn::{
+ ext::IdentExt,
+ parse::{ParseStream, Result},
+ punctuated::Punctuated,
+ Ident, Path, PathArguments, PathSegment, Token,
+};
+
+fn parse_path_segment(input: ParseStream<'_>) -> Result<PathSegment> {
+ if input.peek(Token![super])
+ || input.peek(Token![self])
+ || input.peek(Token![crate])
+ || input.peek(Token![extern])
+ {
+ let ident = input.call(Ident::parse_any)?;
+ return Ok(PathSegment::from(ident));
+ }
+
+ let ident = if input.peek(Token![Self]) {
+ input.call(Ident::parse_any)?
+ } else {
+ input.parse()?
+ };
+
+ if input.peek(Token![::]) && input.peek3(Token![<]) {
+ Ok(PathSegment {
+ ident,
+ arguments: PathArguments::AngleBracketed(input.parse()?),
+ })
+ } else {
+ Ok(PathSegment::from(ident))
+ }
+}
+
+pub(crate) fn parse_path(input: ParseStream<'_>) -> Result<Path> {
+ Ok(Path {
+ leading_colon: input.parse()?,
+ segments: {
+ let mut segments = Punctuated::new();
+ let value = parse_path_segment(input)?;
+ segments.push_value(value);
+ while input.peek(Token![::]) {
+ let punct: Token![::] = input.parse()?;
+ segments.push_punct(punct);
+ let value = parse_path_segment(input)?;
+ segments.push_value(value);
+ }
+ segments
+ },
+ })
+}
diff --git a/syn/.gitignore b/syn/.gitignore
new file mode 100644
index 0000000..9fa6883
--- /dev/null
+++ b/syn/.gitignore
@@ -0,0 +1,3 @@
+target
+Cargo.lock
+tests/rust/*
diff --git a/syn/.travis.yml b/syn/.travis.yml
new file mode 100644
index 0000000..a8719cc
--- /dev/null
+++ b/syn/.travis.yml
@@ -0,0 +1,76 @@
+language: rust
+
+before_script:
+ - set -o errexit
+
+script:
+ - shopt -s expand_aliases
+ - alias build="cargo build ${TARGET+--target=$TARGET}"
+ - build --no-default-features
+ - build
+ - build --features full
+ - build --features 'fold visit visit-mut'
+ - build --features 'full fold visit visit-mut'
+ - build --no-default-features --features derive
+ - build --no-default-features --features 'derive parsing'
+ - build --no-default-features --features 'derive printing'
+ - build --no-default-features --features 'proc-macro parsing printing'
+ - build --no-default-features --features full
+ - build --no-default-features --features 'full parsing'
+ - build --no-default-features --features 'full printing'
+ - build --no-default-features --features 'full parsing printing'
+ - build --no-default-features --features 'fold visit visit-mut parsing printing'
+ - build --no-default-features --features 'full fold visit visit-mut parsing printing'
+
+matrix:
+ include:
+ - rust: nightly
+ name: Tests
+ install:
+ - rustup component add rustc-dev
+ script:
+ - cargo test --all-features --release
+ - rust: nightly
+ - rust: stable
+ - rust: beta
+ - rust: 1.31.0
+ - rust: nightly
+ name: Examples
+ script:
+ - cargo check --manifest-path examples/dump-syntax/Cargo.toml
+ - cargo check --manifest-path examples/heapsize/example/Cargo.toml
+ - cargo check --manifest-path examples/lazy-static/example/Cargo.toml
+ - cargo check --manifest-path examples/trace-var/example/Cargo.toml
+ - rust: nightly
+ name: Codegen
+ script:
+ - (cd codegen && cargo run)
+ - git diff --exit-code
+ - rust: nightly
+ name: Minimal versions
+ script:
+ - cargo update -Z minimal-versions
+ - cargo build --all-features
+ - rust: nightly
+ name: Clippy
+ script:
+ - rustup component add clippy || travis_terminate 0
+ - cargo clippy --all-features
+ - rust: nightly
+ name: WebAssembly
+ env: TARGET=wasm32-unknown-unknown
+ install:
+ - rustup target add "${TARGET}"
+ - rust: nightly
+ name: WASI
+ env: TARGET=wasm32-wasi
+ install:
+ - rustup target add "${TARGET}"
+ allow_failures:
+ - rust: nightly
+ name: Clippy
+ fast_finish: true
+
+env:
+ global:
+ - RUST_MIN_STACK=20000000
diff --git a/syn/Cargo.toml b/syn/Cargo.toml
new file mode 100644
index 0000000..11ad921
--- /dev/null
+++ b/syn/Cargo.toml
@@ -0,0 +1,72 @@
+[package]
+name = "syn"
+version = "1.0.12" # don't forget to update html_root_url and syn.json
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+license = "MIT OR Apache-2.0"
+description = "Parser for Rust source code"
+repository = "https://github.com/dtolnay/syn"
+documentation = "https://docs.rs/syn"
+categories = ["development-tools::procedural-macro-helpers"]
+readme = "README.md"
+include = [
+ "/benches/**",
+ "/build.rs",
+ "/Cargo.toml",
+ "/LICENSE-APACHE",
+ "/LICENSE-MIT",
+ "/README.md",
+ "/src/**",
+ "/tests/**",
+]
+edition = "2018"
+
+[features]
+default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"]
+derive = []
+full = []
+parsing = []
+printing = ["quote"]
+visit = []
+visit-mut = []
+fold = []
+clone-impls = []
+extra-traits = []
+proc-macro = ["proc-macro2/proc-macro", "quote/proc-macro"]
+
+[dependencies]
+proc-macro2 = { version = "1.0.7", default-features = false }
+quote = { version = "1.0", optional = true, default-features = false }
+unicode-xid = "0.2"
+
+[dev-dependencies]
+anyhow = "1.0"
+flate2 = "1.0"
+insta = "0.12"
+rayon = "1.0"
+ref-cast = "1.0"
+regex = "1.0"
+reqwest = { version = "0.10", features = ["blocking"] }
+tar = "0.4"
+termcolor = "1.0"
+walkdir = "2.1"
+
+[[bench]]
+name = "rust"
+harness = false
+required-features = ["full", "parsing"]
+
+[[bench]]
+name = "file"
+required-features = ["full", "parsing"]
+
+[package.metadata.docs.rs]
+all-features = true
+
+[package.metadata.playground]
+all-features = true
+
+[badges]
+travis-ci = { repository = "dtolnay/syn" }
+
+[workspace]
+members = ["dev", "json"]
diff --git a/syn/LICENSE-APACHE b/syn/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/syn/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/syn/LICENSE-MIT b/syn/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/syn/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/syn/README.md b/syn/README.md
new file mode 100644
index 0000000..29a7f32
--- /dev/null
+++ b/syn/README.md
@@ -0,0 +1,291 @@
+Parser for Rust source code
+===========================
+
+[![Build Status](https://api.travis-ci.org/dtolnay/syn.svg?branch=master)](https://travis-ci.org/dtolnay/syn)
+[![Latest Version](https://img.shields.io/crates/v/syn.svg)](https://crates.io/crates/syn)
+[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/syn/1.0/syn/)
+[![Rustc Version 1.31+](https://img.shields.io/badge/rustc-1.31+-lightgray.svg)](https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html)
+
+Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree
+of Rust source code.
+
+Currently this library is geared toward use in Rust procedural macros, but
+contains some APIs that may be useful more generally.
+
+- **Data structures** — Syn provides a complete syntax tree that can represent
+ any valid Rust source code. The syntax tree is rooted at [`syn::File`] which
+ represents a full source file, but there are other entry points that may be
+ useful to procedural macros including [`syn::Item`], [`syn::Expr`] and
+ [`syn::Type`].
+
+- **Derives** — Of particular interest to derive macros is [`syn::DeriveInput`]
+ which is any of the three legal input items to a derive macro. An example
+ below shows using this type in a library that can derive implementations of a
+ user-defined trait.
+
+- **Parsing** — Parsing in Syn is built around [parser functions] with the
+ signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined by
+ Syn is individually parsable and may be used as a building block for custom
+ syntaxes, or you may dream up your own brand new syntax without involving any
+ of our syntax tree types.
+
+- **Location information** — Every token parsed by Syn is associated with a
+ `Span` that tracks line and column information back to the source of that
+ token. These spans allow a procedural macro to display detailed error messages
+ pointing to all the right places in the user's code. There is an example of
+ this below.
+
+- **Feature flags** — Functionality is aggressively feature gated so your
+ procedural macros enable only what they need, and do not pay in compile time
+ for all the rest.
+
+[`syn::File`]: https://docs.rs/syn/1.0/syn/struct.File.html
+[`syn::Item`]: https://docs.rs/syn/1.0/syn/enum.Item.html
+[`syn::Expr`]: https://docs.rs/syn/1.0/syn/enum.Expr.html
+[`syn::Type`]: https://docs.rs/syn/1.0/syn/enum.Type.html
+[`syn::DeriveInput`]: https://docs.rs/syn/1.0/syn/struct.DeriveInput.html
+[parser functions]: https://docs.rs/syn/1.0/syn/parse/index.html
+
+If you get stuck with anything involving procedural macros in Rust I am happy to
+provide help even if the issue is not related to Syn. Please file a ticket in
+this repo.
+
+*Version requirement: Syn supports rustc 1.31 and up.*
+
+[*Release notes*](https://github.com/dtolnay/syn/releases)
+
+<br>
+
+## Resources
+
+The best way to learn about procedural macros is by writing some. Consider
+working through [this procedural macro workshop][workshop] to get familiar with
+the different types of procedural macros. The workshop contains relevant links
+into the Syn documentation as you work through each project.
+
+[workshop]: https://github.com/dtolnay/proc-macro-workshop
+
+<br>
+
+## Example of a derive macro
+
+The canonical derive macro using Syn looks like this. We write an ordinary Rust
+function tagged with a `proc_macro_derive` attribute and the name of the trait
+we are deriving. Any time that derive appears in the user's code, the Rust
+compiler passes their data structure as tokens into our macro. We get to execute
+arbitrary Rust code to figure out what to do with those tokens, then hand some
+tokens back to the compiler to compile into the user's crate.
+
+[`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html
+
+```toml
+[dependencies]
+syn = "1.0"
+quote = "1.0"
+
+[lib]
+proc-macro = true
+```
+
+```rust
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{parse_macro_input, DeriveInput};
+
+#[proc_macro_derive(MyMacro)]
+pub fn my_macro(input: TokenStream) -> TokenStream {
+ // Parse the input tokens into a syntax tree
+ let input = parse_macro_input!(input as DeriveInput);
+
+ // Build the output, possibly using quasi-quotation
+ let expanded = quote! {
+ // ...
+ };
+
+ // Hand the output tokens back to the compiler
+ TokenStream::from(expanded)
+}
+```
+
+The [`heapsize`] example directory shows a complete working implementation of a
+derive macro. It works on any Rust compiler 1.31+. The example derives a
+`HeapSize` trait which computes an estimate of the amount of heap memory owned
+by a value.
+
+[`heapsize`]: examples/heapsize
+
+```rust
+pub trait HeapSize {
+ /// Total number of bytes of heap memory owned by `self`.
+ fn heap_size_of_children(&self) -> usize;
+}
+```
+
+The derive macro allows users to write `#[derive(HeapSize)]` on data structures
+in their program.
+
+```rust
+#[derive(HeapSize)]
+struct Demo<'a, T: ?Sized> {
+ a: Box<T>,
+ b: u8,
+ c: &'a str,
+ d: String,
+}
+```
+
+<br>
+
+## Spans and error reporting
+
+The token-based procedural macro API provides great control over where the
+compiler's error messages are displayed in user code. Consider the error the
+user sees if one of their field types does not implement `HeapSize`.
+
+```rust
+#[derive(HeapSize)]
+struct Broken {
+ ok: String,
+ bad: std::thread::Thread,
+}
+```
+
+By tracking span information all the way through the expansion of a procedural
+macro as shown in the `heapsize` example, token-based macros in Syn are able to
+trigger errors that directly pinpoint the source of the problem.
+
+```
+error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
+ --> src/main.rs:7:5
+ |
+7 | bad: std::thread::Thread,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
+```
+
+<br>
+
+## Parsing a custom syntax
+
+The [`lazy-static`] example directory shows the implementation of a
+`functionlike!(...)` procedural macro in which the input tokens are parsed using
+Syn's parsing API.
+
+[`lazy-static`]: examples/lazy-static
+
+The example reimplements the popular `lazy_static` crate from crates.io as a
+procedural macro.
+
+```
+lazy_static! {
+ static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
+}
+```
+
+The implementation shows how to trigger custom warnings and error messages on
+the macro input.
+
+```
+warning: come on, pick a more creative name
+ --> src/main.rs:10:16
+ |
+10 | static ref FOO: String = "lazy_static".to_owned();
+ | ^^^
+```
+
+<br>
+
+## Testing
+
+When testing macros, we often care not just that the macro can be used
+successfully but also that when the macro is provided with invalid input it
+produces maximally helpful error messages. Consider using the [`trybuild`] crate
+to write tests for errors that are emitted by your macro or errors detected by
+the Rust compiler in the expanded code following misuse of the macro. Such tests
+help avoid regressions from later refactors that mistakenly make an error no
+longer trigger or be less helpful than it used to be.
+
+[`trybuild`]: https://github.com/dtolnay/trybuild
+
+<br>
+
+## Debugging
+
+When developing a procedural macro it can be helpful to look at what the
+generated code looks like. Use `cargo rustc -- -Zunstable-options
+--pretty=expanded` or the [`cargo expand`] subcommand.
+
+[`cargo expand`]: https://github.com/dtolnay/cargo-expand
+
+To show the expanded code for some crate that uses your procedural macro, run
+`cargo expand` from that crate. To show the expanded code for one of your own
+test cases, run `cargo expand --test the_test_case` where the last argument is
+the name of the test file without the `.rs` extension.
+
+This write-up by Brandon W Maister discusses debugging in more detail:
+[Debugging Rust's new Custom Derive system][debugging].
+
+[debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/
+
+<br>
+
+## Optional features
+
+Syn puts a lot of functionality behind optional features in order to optimize
+compile time for the most common use cases. The following features are
+available.
+
+- **`derive`** *(enabled by default)* — Data structures for representing the
+ possible input to a derive macro, including structs and enums and types.
+- **`full`** — Data structures for representing the syntax tree of all valid
+ Rust source code, including items and expressions.
+- **`parsing`** *(enabled by default)* — Ability to parse input tokens into a
+ syntax tree node of a chosen type.
+- **`printing`** *(enabled by default)* — Ability to print a syntax tree node as
+ tokens of Rust source code.
+- **`visit`** — Trait for traversing a syntax tree.
+- **`visit-mut`** — Trait for traversing and mutating in place a syntax tree.
+- **`fold`** — Trait for transforming an owned syntax tree.
+- **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
+ types.
+- **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree
+ types.
+- **`proc-macro`** *(enabled by default)* — Runtime dependency on the dynamic
+ library libproc_macro from rustc toolchain.
+
+<br>
+
+## Proc macro shim
+
+Syn operates on the token representation provided by the [proc-macro2] crate
+from crates.io rather than using the compiler's built in proc-macro crate
+directly. This enables code using Syn to execute outside of the context of a
+procedural macro, such as in unit tests or build.rs, and we avoid needing
+incompatible ecosystems for proc macros vs non-macro use cases.
+
+In general all of your code should be written against proc-macro2 rather than
+proc-macro. The one exception is in the signatures of procedural macro entry
+points, which are required by the language to use `proc_macro::TokenStream`.
+
+The proc-macro2 crate will automatically detect and use the compiler's data
+structures when a procedural macro is active.
+
+[proc-macro2]: https://docs.rs/proc-macro2/1.0.0/proc_macro2/
+
+<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/syn/appveyor.yml b/syn/appveyor.yml
new file mode 100644
index 0000000..020c8ac
--- /dev/null
+++ b/syn/appveyor.yml
@@ -0,0 +1,16 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+
+install:
+ - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
+ - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
+ - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
+ - SET PATH=%PATH%;C:\MinGW\bin
+ - rustc -V
+ - cargo -V
+
+build: false
+
+test_script:
+ - cargo build --all-features
diff --git a/syn/benches/file.rs b/syn/benches/file.rs
new file mode 100644
index 0000000..58ab8df
--- /dev/null
+++ b/syn/benches/file.rs
@@ -0,0 +1,30 @@
+// $ cargo bench --features full --bench file
+
+#![feature(rustc_private, test)]
+#![recursion_limit = "1024"]
+
+extern crate test;
+
+#[macro_use]
+#[path = "../tests/macros/mod.rs"]
+mod macros;
+
+#[path = "../tests/common/mod.rs"]
+mod common;
+#[path = "../tests/repo/mod.rs"]
+pub mod repo;
+
+use proc_macro2::TokenStream;
+use std::fs;
+use std::str::FromStr;
+use test::Bencher;
+
+const FILE: &str = "tests/rust/src/libcore/str/mod.rs";
+
+#[bench]
+fn parse_file(b: &mut Bencher) {
+ repo::clone_rust();
+ let content = fs::read_to_string(FILE).unwrap();
+ let tokens = TokenStream::from_str(&content).unwrap();
+ b.iter(|| syn::parse2::<syn::File>(tokens.clone()));
+}
diff --git a/syn/benches/rust.rs b/syn/benches/rust.rs
new file mode 100644
index 0000000..941ecb9
--- /dev/null
+++ b/syn/benches/rust.rs
@@ -0,0 +1,158 @@
+// $ cargo bench --features full --bench rust
+//
+// Syn only, useful for profiling:
+// $ RUSTFLAGS='--cfg syn_only' cargo build --release --features full --bench rust
+
+#![cfg_attr(not(syn_only), feature(rustc_private))]
+#![recursion_limit = "1024"]
+
+#[macro_use]
+#[path = "../tests/macros/mod.rs"]
+mod macros;
+
+#[path = "../tests/common/mod.rs"]
+mod common;
+#[path = "../tests/repo/mod.rs"]
+mod repo;
+
+use std::fs;
+use std::time::{Duration, Instant};
+
+#[cfg(not(syn_only))]
+mod tokenstream_parse {
+ use proc_macro2::TokenStream;
+ use std::str::FromStr;
+
+ pub fn bench(content: &str) -> Result<(), ()> {
+ TokenStream::from_str(content).map(drop).map_err(drop)
+ }
+}
+
+mod syn_parse {
+ pub fn bench(content: &str) -> Result<(), ()> {
+ syn::parse_file(content).map(drop).map_err(drop)
+ }
+}
+
+#[cfg(not(syn_only))]
+mod libsyntax_parse {
+ extern crate rustc_data_structures;
+ extern crate rustc_parse;
+ extern crate rustc_span;
+ extern crate syntax;
+
+ use rustc_data_structures::sync::Lrc;
+ use rustc_span::FileName;
+ use syntax::edition::Edition;
+ use syntax::errors::{emitter::Emitter, Diagnostic, Handler};
+ use syntax::sess::ParseSess;
+ use syntax::source_map::{FilePathMapping, SourceMap};
+
+ pub fn bench(content: &str) -> Result<(), ()> {
+ struct SilentEmitter;
+
+ impl Emitter for SilentEmitter {
+ fn emit_diagnostic(&mut self, _diag: &Diagnostic) {}
+ fn source_map(&self) -> Option<&Lrc<SourceMap>> {
+ None
+ }
+ }
+
+ syntax::with_globals(Edition::Edition2018, || {
+ let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+ let emitter = Box::new(SilentEmitter);
+ let handler = Handler::with_emitter(false, None, emitter);
+ let sess = ParseSess::with_span_handler(handler, cm);
+ if let Err(mut diagnostic) = rustc_parse::parse_crate_from_source_str(
+ FileName::Custom("bench".to_owned()),
+ content.to_owned(),
+ &sess,
+ ) {
+ diagnostic.cancel();
+ return Err(());
+ };
+ Ok(())
+ })
+ }
+}
+
+#[cfg(not(syn_only))]
+mod read_from_disk {
+ pub fn bench(content: &str) -> Result<(), ()> {
+ let _ = content;
+ Ok(())
+ }
+}
+
+fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
+ let begin = Instant::now();
+ let mut success = 0;
+ let mut total = 0;
+
+ walkdir::WalkDir::new("tests/rust/src")
+ .into_iter()
+ .filter_entry(repo::base_dir_filter)
+ .for_each(|entry| {
+ let entry = entry.unwrap();
+ let path = entry.path();
+ if path.is_dir() {
+ return;
+ }
+ let content = fs::read_to_string(path).unwrap();
+ let ok = codepath(&content).is_ok();
+ success += ok as usize;
+ total += 1;
+ if !ok {
+ eprintln!("FAIL {}", path.display());
+ }
+ });
+
+ assert_eq!(success, total);
+ begin.elapsed()
+}
+
+fn main() {
+ repo::clone_rust();
+
+ macro_rules! testcases {
+ ($($(#[$cfg:meta])* $name:path,)*) => {
+ vec![
+ $(
+ $(#[$cfg])*
+ (stringify!($name), $name as fn(&str) -> Result<(), ()>),
+ )*
+ ]
+ };
+ }
+
+ #[cfg(not(syn_only))]
+ {
+ let mut lines = 0;
+ let mut files = 0;
+ exec(|content| {
+ lines += content.lines().count();
+ files += 1;
+ Ok(())
+ });
+ eprintln!("\n{} lines in {} files", lines, files);
+ }
+
+ for (name, f) in testcases!(
+ #[cfg(not(syn_only))]
+ read_from_disk::bench,
+ #[cfg(not(syn_only))]
+ tokenstream_parse::bench,
+ syn_parse::bench,
+ #[cfg(not(syn_only))]
+ libsyntax_parse::bench,
+ ) {
+ eprint!("{:20}", format!("{}:", name));
+ let elapsed = exec(f);
+ eprintln!(
+ "elapsed={}.{:03}s",
+ elapsed.as_secs(),
+ elapsed.subsec_millis(),
+ );
+ }
+ eprintln!();
+}
diff --git a/syn/build.rs b/syn/build.rs
new file mode 100644
index 0000000..c6040c1
--- /dev/null
+++ b/syn/build.rs
@@ -0,0 +1,63 @@
+use std::env;
+use std::process::Command;
+use std::str::{self, FromStr};
+
+// The rustc-cfg strings below are *not* public API. Please let us know by
+// opening a GitHub issue if your build environment requires some way to enable
+// these cfgs other than by executing our build script.
+fn main() {
+ let compiler = match rustc_version() {
+ Some(compiler) => compiler,
+ None => return,
+ };
+
+ if compiler.minor < 36 {
+ println!("cargo:rustc-cfg=syn_omit_await_from_token_macro");
+ }
+
+ if !compiler.nightly {
+ println!("cargo:rustc-cfg=syn_disable_nightly_tests");
+ }
+}
+
+struct Compiler {
+ minor: u32,
+ nightly: bool,
+}
+
+fn rustc_version() -> Option<Compiler> {
+ let rustc = match env::var_os("RUSTC") {
+ Some(rustc) => rustc,
+ None => return None,
+ };
+
+ let output = match Command::new(rustc).arg("--version").output() {
+ Ok(output) => output,
+ Err(_) => return None,
+ };
+
+ let version = match str::from_utf8(&output.stdout) {
+ Ok(version) => version,
+ Err(_) => return None,
+ };
+
+ let mut pieces = version.split('.');
+ if pieces.next() != Some("rustc 1") {
+ return None;
+ }
+
+ let next = match pieces.next() {
+ Some(next) => next,
+ None => return None,
+ };
+
+ let minor = match u32::from_str(next) {
+ Ok(minor) => minor,
+ Err(_) => return None,
+ };
+
+ Some(Compiler {
+ minor,
+ nightly: version.contains("nightly"),
+ })
+}
diff --git a/syn/codegen/Cargo.toml b/syn/codegen/Cargo.toml
new file mode 100644
index 0000000..44d890b
--- /dev/null
+++ b/syn/codegen/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+name = "syn-internal-codegen"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>", "Nika Layzell <nika@thelayzells.com>"]
+edition = "2018"
+
+publish = false # this is an internal crate which should never be published
+
+[dependencies]
+anyhow = "1.0"
+color-backtrace = "0.2"
+indexmap = { version = "1.0", features = ["serde-1"] }
+inflections = "1.1"
+proc-macro2 = { version = "1.0", features = ["span-locations"] }
+quote = "1.0"
+rustfmt = { package = "rustfmt-nightly", git = "https://github.com/rust-lang-nursery/rustfmt" }
+semver = { version = "0.9", features = ["serde"] }
+serde = { version = "1.0.88", features = ["derive"] }
+serde_json = "1.0.38"
+syn-codegen = { path = "../json" }
+syn = { path = "..", features = ["full", "extra-traits"] }
+thiserror = "1.0"
+toml = "0.4.10"
+
+# work around https://github.com/crossbeam-rs/crossbeam/issues/435
+# until https://github.com/BurntSushi/ripgrep/pull/1427 is released
+crossbeam-utils = "=0.6.5"
+
+[workspace]
+# Prefer that `cargo clean` in syn's directory does not require a rebuild of
+# rustfmt in the codegen directory.
diff --git a/syn/codegen/README.md b/syn/codegen/README.md
new file mode 100644
index 0000000..df46bd2
--- /dev/null
+++ b/syn/codegen/README.md
@@ -0,0 +1,12 @@
+# syn_codegen
+
+This is an internal (not published on crates.io) crate which is used to generate
+the files in the `gen/` directory of `syn`. It is used to ensure that the
+implementations for `Fold`, `Visit`, and `VisitMut` remain in sync with the
+actual AST.
+
+To run this program, run `cargo run` in this directory, and the `gen/` folder
+will be re-generated.
+
+This program is slow, and is therefore not run when building `syn` as part of
+the build script to save on compile time.
diff --git a/syn/codegen/src/debug.rs b/syn/codegen/src/debug.rs
new file mode 100644
index 0000000..9193881
--- /dev/null
+++ b/syn/codegen/src/debug.rs
@@ -0,0 +1,308 @@
+use crate::file;
+use anyhow::Result;
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::quote;
+use syn::Index;
+use syn_codegen::{Data, Definitions, Node, Type};
+
+const DEBUG_SRC: &str = "../tests/debug/gen.rs";
+
+fn rust_type(ty: &Type) -> TokenStream {
+ match ty {
+ Type::Syn(ty) => {
+ let ident = Ident::new(ty, Span::call_site());
+ quote!(syn::#ident)
+ }
+ Type::Std(ty) => {
+ let ident = Ident::new(ty, Span::call_site());
+ quote!(#ident)
+ }
+ Type::Ext(ty) => {
+ let ident = Ident::new(ty, Span::call_site());
+ quote!(proc_macro2::#ident)
+ }
+ Type::Token(ty) | Type::Group(ty) => {
+ let ident = Ident::new(ty, Span::call_site());
+ quote!(syn::token::#ident)
+ }
+ Type::Punctuated(ty) => {
+ let element = rust_type(&ty.element);
+ let punct = Ident::new(&ty.punct, Span::call_site());
+ quote!(syn::punctuated::Punctuated<#element, #punct>)
+ }
+ Type::Option(ty) => {
+ let inner = rust_type(ty);
+ quote!(Option<#inner>)
+ }
+ Type::Box(ty) => {
+ let inner = rust_type(ty);
+ quote!(Box<#inner>)
+ }
+ Type::Vec(ty) => {
+ let inner = rust_type(ty);
+ quote!(Vec<#inner>)
+ }
+ Type::Tuple(ty) => {
+ let inner = ty.iter().map(rust_type);
+ quote!((#(#inner,)*))
+ }
+ }
+}
+
+fn is_printable(ty: &Type) -> bool {
+ match ty {
+ Type::Ext(name) => name != "Span",
+ Type::Box(ty) => is_printable(ty),
+ Type::Tuple(ty) => ty.iter().any(is_printable),
+ Type::Token(_) | Type::Group(_) => false,
+ Type::Syn(name) => name != "Reserved",
+ Type::Std(_) | Type::Punctuated(_) | Type::Option(_) | Type::Vec(_) => true,
+ }
+}
+
+fn format_field(val: &TokenStream, ty: &Type) -> Option<TokenStream> {
+ if !is_printable(ty) {
+ return None;
+ }
+ let format = match ty {
+ Type::Option(ty) => {
+ let inner = quote!(_val);
+ let format = format_field(&inner, ty).map(|format| {
+ quote! {
+ formatter.write_str("(")?;
+ Debug::fmt(#format, formatter)?;
+ formatter.write_str(")")?;
+ }
+ });
+ let ty = rust_type(ty);
+ quote!({
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Option<#ty>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match &self.0 {
+ Some(#inner) => {
+ formatter.write_str("Some")?;
+ #format
+ Ok(())
+ }
+ None => formatter.write_str("None"),
+ }
+ }
+ }
+ Print::ref_cast(#val)
+ })
+ }
+ Type::Tuple(ty) => {
+ let printable: Vec<TokenStream> = ty
+ .iter()
+ .enumerate()
+ .filter_map(|(i, ty)| {
+ let index = Index::from(i);
+ let val = quote!(&#val.#index);
+ format_field(&val, ty)
+ })
+ .collect();
+ if printable.len() == 1 {
+ printable.into_iter().next().unwrap()
+ } else {
+ quote! {
+ &(#(#printable),*)
+ }
+ }
+ }
+ _ => quote! { Lite(#val) },
+ };
+ Some(format)
+}
+
+fn syntax_tree_enum<'a>(outer: &str, inner: &str, fields: &'a [Type]) -> Option<&'a str> {
+ if fields.len() != 1 {
+ return None;
+ }
+ const WHITELIST: &[&str] = &["PathArguments", "Visibility"];
+ match &fields[0] {
+ Type::Syn(ty) if WHITELIST.contains(&outer) || outer.to_owned() + inner == *ty => Some(ty),
+ _ => None,
+ }
+}
+
+fn lookup<'a>(defs: &'a Definitions, name: &str) -> &'a Node {
+ for node in &defs.types {
+ if node.ident == name {
+ return node;
+ }
+ }
+ panic!("not found: {}", name)
+}
+
+fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream {
+ let ident = Ident::new(&node.ident, Span::call_site());
+
+ match &node.data {
+ Data::Enum(variants) => {
+ let arms = variants.iter().map(|(v, fields)| {
+ let variant = Ident::new(v, Span::call_site());
+ if fields.is_empty() {
+ quote! {
+ syn::#ident::#variant => formatter.write_str(#v),
+ }
+ } else if let Some(inner) = syntax_tree_enum(name, v, fields) {
+ let path = format!("{}::{}", name, v);
+ let format = expand_impl_body(defs, lookup(defs, inner), &path);
+ quote! {
+ syn::#ident::#variant(_val) => {
+ #format
+ }
+ }
+ } else if fields.len() == 1 {
+ let ty = &fields[0];
+ let val = quote!(_val);
+ let format = format_field(&val, ty).map(|format| {
+ quote! {
+ formatter.write_str("(")?;
+ Debug::fmt(#format, formatter)?;
+ formatter.write_str(")")?;
+ }
+ });
+ quote! {
+ syn::#ident::#variant(_val) => {
+ formatter.write_str(#v)?;
+ #format
+ Ok(())
+ }
+ }
+ } else {
+ let pats = (0..fields.len())
+ .map(|i| Ident::new(&format!("_v{}", i), Span::call_site()));
+ let fields = fields.iter().enumerate().filter_map(|(i, ty)| {
+ let index = Ident::new(&format!("_v{}", i), Span::call_site());
+ let val = quote!(#index);
+ let format = format_field(&val, ty)?;
+ Some(quote! {
+ formatter.field(#format);
+ })
+ });
+ quote! {
+ syn::#ident::#variant(#(#pats),*) => {
+ let mut formatter = formatter.debug_tuple(#v);
+ #(#fields)*
+ formatter.finish()
+ }
+ }
+ }
+ });
+ let nonexhaustive = if node.exhaustive {
+ None
+ } else {
+ Some(quote!(_ => unreachable!()))
+ };
+ quote! {
+ match _val {
+ #(#arms)*
+ #nonexhaustive
+ }
+ }
+ }
+ Data::Struct(fields) => {
+ let fields = fields.iter().filter_map(|(f, ty)| {
+ let ident = Ident::new(f, Span::call_site());
+ if let Type::Option(ty) = ty {
+ let inner = quote!(_val);
+ let format = format_field(&inner, ty).map(|format| {
+ quote! {
+ let #inner = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(#format, formatter)?;
+ formatter.write_str(")")?;
+ }
+ });
+ let ty = rust_type(ty);
+ Some(quote! {
+ if let Some(val) = &_val.#ident {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(#ty);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ #format
+ Ok(())
+ }
+ }
+ formatter.field(#f, Print::ref_cast(val));
+ }
+ })
+ } else {
+ let val = quote!(&_val.#ident);
+ let format = format_field(&val, ty)?;
+ let mut call = quote! {
+ formatter.field(#f, #format);
+ };
+ if let Type::Vec(_) | Type::Punctuated(_) = ty {
+ call = quote! {
+ if !_val.#ident.is_empty() {
+ #call
+ }
+ };
+ }
+ Some(call)
+ }
+ });
+ quote! {
+ let mut formatter = formatter.debug_struct(#name);
+ #(#fields)*
+ formatter.finish()
+ }
+ }
+ Data::Private => {
+ if node.ident == "LitInt" || node.ident == "LitFloat" {
+ quote! {
+ write!(formatter, "{}", _val)
+ }
+ } else {
+ quote! {
+ write!(formatter, "{:?}", _val.value())
+ }
+ }
+ }
+ }
+}
+
+fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
+ if node.ident == "Reserved" {
+ return TokenStream::new();
+ }
+
+ let ident = Ident::new(&node.ident, Span::call_site());
+ let body = expand_impl_body(defs, node, &node.ident);
+
+ quote! {
+ impl Debug for Lite<syn::#ident> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ #body
+ }
+ }
+ }
+}
+
+pub fn generate(defs: &Definitions) -> Result<()> {
+ let mut impls = TokenStream::new();
+ for node in &defs.types {
+ impls.extend(expand_impl(&defs, node));
+ }
+
+ file::write(
+ DEBUG_SRC,
+ quote! {
+ use super::{Lite, RefCast};
+ use std::fmt::{self, Debug};
+
+ #impls
+ },
+ )?;
+
+ Ok(())
+}
diff --git a/syn/codegen/src/file.rs b/syn/codegen/src/file.rs
new file mode 100644
index 0000000..5521d75
--- /dev/null
+++ b/syn/codegen/src/file.rs
@@ -0,0 +1,32 @@
+use anyhow::Result;
+use proc_macro2::TokenStream;
+use std::fs;
+use std::io::Write;
+use std::path::Path;
+
+pub fn write<P: AsRef<Path>>(path: P, content: TokenStream) -> Result<()> {
+ let mut formatted = Vec::new();
+ writeln!(
+ formatted,
+ "// This file is @generated by syn-internal-codegen."
+ )?;
+ writeln!(formatted, "// It is not intended for manual editing.")?;
+ writeln!(formatted)?;
+
+ let mut config = rustfmt::Config::default();
+ config.set().emit_mode(rustfmt::EmitMode::Stdout);
+ config.set().verbose(rustfmt::Verbosity::Quiet);
+ config.set().format_macro_matchers(true);
+ config.set().normalize_doc_attributes(true);
+
+ let mut session = rustfmt::Session::new(config, Some(&mut formatted));
+ session.format(rustfmt::Input::Text(content.to_string()))?;
+ drop(session);
+
+ if path.as_ref().is_file() && fs::read(&path)? == formatted {
+ return Ok(());
+ }
+
+ fs::write(path, formatted)?;
+ Ok(())
+}
diff --git a/syn/codegen/src/fold.rs b/syn/codegen/src/fold.rs
new file mode 100644
index 0000000..6914d76
--- /dev/null
+++ b/syn/codegen/src/fold.rs
@@ -0,0 +1,284 @@
+use crate::{file, full, gen};
+use anyhow::Result;
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::quote;
+use syn::Index;
+use syn_codegen::{Data, Definitions, Features, Node, Type};
+
+const FOLD_SRC: &str = "../src/gen/fold.rs";
+
+fn simple_visit(item: &str, name: &TokenStream) -> TokenStream {
+ let ident = gen::under_name(item);
+ let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
+ quote! {
+ f.#method(#name)
+ }
+}
+
+fn visit(
+ ty: &Type,
+ features: &Features,
+ defs: &Definitions,
+ name: &TokenStream,
+) -> Option<TokenStream> {
+ match ty {
+ Type::Box(t) => {
+ let res = visit(t, features, defs, &quote!(*#name))?;
+ Some(quote! {
+ Box::new(#res)
+ })
+ }
+ Type::Vec(t) => {
+ let operand = quote!(it);
+ let val = visit(t, features, defs, &operand)?;
+ Some(quote! {
+ FoldHelper::lift(#name, |it| { #val })
+ })
+ }
+ Type::Punctuated(p) => {
+ let operand = quote!(it);
+ let val = visit(&p.element, features, defs, &operand)?;
+ Some(quote! {
+ FoldHelper::lift(#name, |it| { #val })
+ })
+ }
+ Type::Option(t) => {
+ let it = quote!(it);
+ let val = visit(t, features, defs, &it)?;
+ Some(quote! {
+ (#name).map(|it| { #val })
+ })
+ }
+ Type::Tuple(t) => {
+ let mut code = TokenStream::new();
+ for (i, elem) in t.iter().enumerate() {
+ let i = Index::from(i);
+ let it = quote!((#name).#i);
+ let val = visit(elem, features, defs, &it).unwrap_or(it);
+ code.extend(val);
+ code.extend(quote!(,));
+ }
+ Some(quote! {
+ (#code)
+ })
+ }
+ Type::Token(t) => {
+ let repr = &defs.tokens[t];
+ let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+ let spans = if is_keyword {
+ quote!(span)
+ } else {
+ quote!(spans)
+ };
+ let ty = if repr == "await" {
+ quote!(crate::token::Await)
+ } else {
+ syn::parse_str(&format!("Token![{}]", repr)).unwrap()
+ };
+ Some(quote! {
+ #ty(tokens_helper(f, &#name.#spans))
+ })
+ }
+ Type::Group(t) => {
+ let ty = Ident::new(t, Span::call_site());
+ Some(quote! {
+ #ty(tokens_helper(f, &#name.span))
+ })
+ }
+ Type::Syn(t) => {
+ fn requires_full(features: &Features) -> bool {
+ features.any.contains("full") && features.any.len() == 1
+ }
+ let mut res = simple_visit(t, name);
+ let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
+ if requires_full(&target.features) && !requires_full(features) {
+ res = quote!(full!(#res));
+ }
+ Some(res)
+ }
+ Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+ Type::Ext(_) | Type::Std(_) => None,
+ }
+}
+
+fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) {
+ let under_name = gen::under_name(&s.ident);
+ let ty = Ident::new(&s.ident, Span::call_site());
+ let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
+
+ let mut fold_impl = TokenStream::new();
+
+ match &s.data {
+ Data::Enum(variants) => {
+ let mut fold_variants = TokenStream::new();
+
+ for (variant, fields) in variants {
+ let variant_ident = Ident::new(variant, Span::call_site());
+
+ if fields.is_empty() {
+ fold_variants.extend(quote! {
+ #ty::#variant_ident => {
+ #ty::#variant_ident
+ }
+ });
+ } else {
+ let mut bind_fold_fields = TokenStream::new();
+ let mut fold_fields = TokenStream::new();
+
+ for (idx, ty) in fields.iter().enumerate() {
+ let name = format!("_binding_{}", idx);
+ let binding = Ident::new(&name, Span::call_site());
+
+ bind_fold_fields.extend(quote! {
+ #binding,
+ });
+
+ let owned_binding = quote!(#binding);
+
+ fold_fields.extend(
+ visit(ty, &s.features, defs, &owned_binding).unwrap_or(owned_binding),
+ );
+
+ fold_fields.extend(quote!(,));
+ }
+
+ fold_variants.extend(quote! {
+ #ty::#variant_ident(#bind_fold_fields) => {
+ #ty::#variant_ident(
+ #fold_fields
+ )
+ }
+ });
+ }
+ }
+
+ let nonexhaustive = if s.exhaustive {
+ None
+ } else {
+ Some(quote!(_ => unreachable!()))
+ };
+
+ fold_impl.extend(quote! {
+ match node {
+ #fold_variants
+ #nonexhaustive
+ }
+ });
+ }
+ Data::Struct(fields) => {
+ let mut fold_fields = TokenStream::new();
+
+ for (field, ty) in fields {
+ let id = Ident::new(&field, Span::call_site());
+ let ref_toks = quote!(node.#id);
+
+ if let Type::Syn(ty) = ty {
+ if ty == "Reserved" {
+ fold_fields.extend(quote! {
+ #id: #ref_toks,
+ });
+ continue;
+ }
+ }
+
+ let fold = visit(&ty, &s.features, defs, &ref_toks).unwrap_or(ref_toks);
+
+ fold_fields.extend(quote! {
+ #id: #fold,
+ });
+ }
+
+ if !fields.is_empty() {
+ fold_impl.extend(quote! {
+ #ty {
+ #fold_fields
+ }
+ })
+ } else {
+ if ty == "Ident" {
+ fold_impl.extend(quote! {
+ let mut node = node;
+ let span = f.fold_span(node.span());
+ node.set_span(span);
+ });
+ }
+ fold_impl.extend(quote! {
+ node
+ });
+ }
+ }
+ Data::Private => {
+ if ty == "Ident" {
+ fold_impl.extend(quote! {
+ let mut node = node;
+ let span = f.fold_span(node.span());
+ node.set_span(span);
+ });
+ }
+ fold_impl.extend(quote! {
+ node
+ });
+ }
+ }
+
+ let fold_span_only =
+ s.data == Data::Private && !gen::TERMINAL_TYPES.contains(&s.ident.as_str());
+ if fold_span_only {
+ fold_impl = quote! {
+ let span = f.fold_span(node.span());
+ let mut node = node;
+ node.set_span(span);
+ node
+ };
+ }
+
+ traits.extend(quote! {
+ fn #fold_fn(&mut self, i: #ty) -> #ty {
+ #fold_fn(self, i)
+ }
+ });
+
+ impls.extend(quote! {
+ pub fn #fold_fn<F>(f: &mut F, node: #ty) -> #ty
+ where
+ F: Fold + ?Sized,
+ {
+ #fold_impl
+ }
+ });
+}
+
+pub fn generate(defs: &Definitions) -> Result<()> {
+ let (traits, impls) = gen::traverse(defs, node);
+ let full_macro = full::get_macro();
+ file::write(
+ FOLD_SRC,
+ quote! {
+ // Unreachable code is generated sometimes without the full feature.
+ #![allow(unreachable_code, unused_variables)]
+
+ use crate::*;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use crate::token::{Brace, Bracket, Paren, Group};
+ use proc_macro2::Span;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use crate::gen::helper::fold::*;
+
+ #full_macro
+
+ /// Syntax tree traversal to transform the nodes of an owned syntax tree.
+ ///
+ /// See the [module documentation] for details.
+ ///
+ /// [module documentation]: self
+ ///
+ /// *This trait is available if Syn is built with the `"fold"` feature.*
+ pub trait Fold {
+ #traits
+ }
+
+ #impls
+ },
+ )?;
+ Ok(())
+}
diff --git a/syn/codegen/src/full.rs b/syn/codegen/src/full.rs
new file mode 100644
index 0000000..a410031
--- /dev/null
+++ b/syn/codegen/src/full.rs
@@ -0,0 +1,20 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+
+pub fn get_macro() -> TokenStream {
+ quote! {
+ #[cfg(feature = "full")]
+ macro_rules! full {
+ ($e:expr) => {
+ $e
+ };
+ }
+
+ #[cfg(all(feature = "derive", not(feature = "full")))]
+ macro_rules! full {
+ ($e:expr) => {
+ unreachable!()
+ };
+ }
+ }
+}
diff --git a/syn/codegen/src/gen.rs b/syn/codegen/src/gen.rs
new file mode 100644
index 0000000..ef43182
--- /dev/null
+++ b/syn/codegen/src/gen.rs
@@ -0,0 +1,45 @@
+use inflections::Inflect;
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::quote;
+use syn_codegen::{Data, Definitions, Features, Node};
+
+pub const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
+
+pub fn under_name(name: &str) -> Ident {
+ Ident::new(&name.to_snake_case(), Span::call_site())
+}
+
+pub fn traverse(
+ defs: &Definitions,
+ node: fn(&mut TokenStream, &mut TokenStream, &Node, &Definitions),
+) -> (TokenStream, TokenStream) {
+ let mut types = defs.types.clone();
+ for terminal in TERMINAL_TYPES {
+ types.push(Node {
+ ident: terminal.to_string(),
+ features: Features::default(),
+ data: Data::Private,
+ exhaustive: true,
+ });
+ }
+ types.sort_by(|a, b| a.ident.cmp(&b.ident));
+
+ let mut traits = TokenStream::new();
+ let mut impls = TokenStream::new();
+ for s in types {
+ if s.ident == "Reserved" {
+ continue;
+ }
+ let features = &s.features.any;
+ let features = match features.len() {
+ 0 => quote!(),
+ 1 => quote!(#[cfg(feature = #(#features)*)]),
+ _ => quote!(#[cfg(any(#(feature = #features),*))]),
+ };
+ traits.extend(features.clone());
+ impls.extend(features);
+ node(&mut traits, &mut impls, &s, defs);
+ }
+
+ (traits, impls)
+}
diff --git a/syn/codegen/src/json.rs b/syn/codegen/src/json.rs
new file mode 100644
index 0000000..53904bf
--- /dev/null
+++ b/syn/codegen/src/json.rs
@@ -0,0 +1,18 @@
+use anyhow::Result;
+use std::fs;
+use std::path::Path;
+use syn_codegen::Definitions;
+
+pub fn generate(defs: &Definitions) -> Result<()> {
+ let mut j = serde_json::to_string_pretty(&defs)?;
+ j.push('\n');
+
+ let check: Definitions = serde_json::from_str(&j)?;
+ assert_eq!(*defs, check);
+
+ let codegen_root = Path::new(env!("CARGO_MANIFEST_DIR"));
+ let json_path = codegen_root.join("../syn.json");
+ fs::write(json_path, j)?;
+
+ Ok(())
+}
diff --git a/syn/codegen/src/main.rs b/syn/codegen/src/main.rs
new file mode 100644
index 0000000..9b1b5dd
--- /dev/null
+++ b/syn/codegen/src/main.rs
@@ -0,0 +1,36 @@
+// This crate crawls the Syn source directory to find all structs and enums that
+// form the Syn syntax tree.
+//
+// A machine-readable representation of the syntax tree is saved to syn.json in
+// the repo root for other code generation tools to consume. The syn-codegen
+// crate (https://docs.rs/syn-codegen/) provides the data structures for parsing
+// and making use of syn.json from Rust code.
+//
+// Finally this crate generates the Visit, VisitMut, and Fold traits in Syn
+// programmatically from the syntax tree description.
+
+#![recursion_limit = "128"]
+#![allow(clippy::needless_pass_by_value)]
+
+mod debug;
+mod file;
+mod fold;
+mod full;
+mod gen;
+mod json;
+mod operand;
+mod parse;
+mod version;
+mod visit;
+mod visit_mut;
+
+fn main() -> anyhow::Result<()> {
+ color_backtrace::install();
+ let defs = parse::parse()?;
+ json::generate(&defs)?;
+ fold::generate(&defs)?;
+ visit::generate(&defs)?;
+ visit_mut::generate(&defs)?;
+ debug::generate(&defs)?;
+ Ok(())
+}
diff --git a/syn/codegen/src/operand.rs b/syn/codegen/src/operand.rs
new file mode 100644
index 0000000..db3bd18
--- /dev/null
+++ b/syn/codegen/src/operand.rs
@@ -0,0 +1,38 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+
+pub enum Operand {
+ Borrowed(TokenStream),
+ Owned(TokenStream),
+}
+
+pub use self::Operand::*;
+
+impl Operand {
+ pub fn tokens(&self) -> &TokenStream {
+ match self {
+ Borrowed(n) | Owned(n) => n,
+ }
+ }
+
+ pub fn ref_tokens(&self) -> TokenStream {
+ match self {
+ Borrowed(n) => n.clone(),
+ Owned(n) => quote!(&#n),
+ }
+ }
+
+ pub fn ref_mut_tokens(&self) -> TokenStream {
+ match self {
+ Borrowed(n) => n.clone(),
+ Owned(n) => quote!(&mut #n),
+ }
+ }
+
+ pub fn owned_tokens(&self) -> TokenStream {
+ match self {
+ Borrowed(n) => quote!(*#n),
+ Owned(n) => n.clone(),
+ }
+ }
+}
diff --git a/syn/codegen/src/parse.rs b/syn/codegen/src/parse.rs
new file mode 100644
index 0000000..cdd6085
--- /dev/null
+++ b/syn/codegen/src/parse.rs
@@ -0,0 +1,657 @@
+use crate::version;
+use anyhow::{bail, Result};
+use indexmap::IndexMap;
+use quote::quote;
+use syn::parse::Parser;
+use syn::{parse_quote, Data, DataStruct, DeriveInput, Ident, Item};
+use syn_codegen as types;
+use thiserror::Error;
+
+use std::collections::BTreeMap;
+use std::fs;
+use std::path::{Path, PathBuf};
+
+const SYN_CRATE_ROOT: &str = "../src/lib.rs";
+const TOKEN_SRC: &str = "../src/token.rs";
+const IGNORED_MODS: &[&str] = &["fold", "visit", "visit_mut"];
+const EXTRA_TYPES: &[&str] = &["Lifetime"];
+const NONEXHAUSTIVE: &str = "__Nonexhaustive";
+
+// NOTE: BTreeMap is used here instead of HashMap to have deterministic output.
+type ItemLookup = BTreeMap<Ident, AstItem>;
+type TokenLookup = BTreeMap<String, String>;
+
+/// Parse the contents of `src` and return a list of AST types.
+pub fn parse() -> Result<types::Definitions> {
+ let mut item_lookup = BTreeMap::new();
+ load_file(SYN_CRATE_ROOT, &[], &mut item_lookup)?;
+
+ let token_lookup = load_token_file(TOKEN_SRC)?;
+
+ let version = version::get()?;
+
+ let types = item_lookup
+ .values()
+ .map(|item| introspect_item(item, &item_lookup, &token_lookup))
+ .collect();
+
+ let tokens = token_lookup
+ .into_iter()
+ .map(|(name, ty)| (ty, name))
+ .collect();
+
+ Ok(types::Definitions {
+ version,
+ types,
+ tokens,
+ })
+}
+
+/// Data extracted from syn source
+#[derive(Clone)]
+pub struct AstItem {
+ ast: DeriveInput,
+ features: Vec<syn::Attribute>,
+}
+
+fn introspect_item(item: &AstItem, items: &ItemLookup, tokens: &TokenLookup) -> types::Node {
+ let features = introspect_features(&item.features);
+
+ match &item.ast.data {
+ Data::Enum(ref data) => types::Node {
+ ident: item.ast.ident.to_string(),
+ features,
+ data: types::Data::Enum(introspect_enum(data, items, tokens)),
+ exhaustive: data.variants.iter().all(|v| v.ident != NONEXHAUSTIVE),
+ },
+ Data::Struct(ref data) => types::Node {
+ ident: item.ast.ident.to_string(),
+ features,
+ data: {
+ if data.fields.iter().all(|f| is_pub(&f.vis)) {
+ types::Data::Struct(introspect_struct(data, items, tokens))
+ } else {
+ types::Data::Private
+ }
+ },
+ exhaustive: true,
+ },
+ Data::Union(..) => panic!("Union not supported"),
+ }
+}
+
+fn introspect_enum(
+ item: &syn::DataEnum,
+ items: &ItemLookup,
+ tokens: &TokenLookup,
+) -> types::Variants {
+ item.variants
+ .iter()
+ .filter_map(|variant| {
+ if variant.ident == NONEXHAUSTIVE {
+ return None;
+ }
+ let fields = match &variant.fields {
+ syn::Fields::Unnamed(fields) => fields
+ .unnamed
+ .iter()
+ .map(|field| introspect_type(&field.ty, items, tokens))
+ .collect(),
+ syn::Fields::Unit => vec![],
+ _ => panic!("Enum representation not supported"),
+ };
+ Some((variant.ident.to_string(), fields))
+ })
+ .collect()
+}
+
+fn introspect_struct(
+ item: &syn::DataStruct,
+ items: &ItemLookup,
+ tokens: &TokenLookup,
+) -> types::Fields {
+ match &item.fields {
+ syn::Fields::Named(fields) => fields
+ .named
+ .iter()
+ .map(|field| {
+ (
+ field.ident.as_ref().unwrap().to_string(),
+ introspect_type(&field.ty, items, tokens),
+ )
+ })
+ .collect(),
+ syn::Fields::Unit => IndexMap::new(),
+ _ => panic!("Struct representation not supported"),
+ }
+}
+
+fn introspect_type(item: &syn::Type, items: &ItemLookup, tokens: &TokenLookup) -> types::Type {
+ match item {
+ syn::Type::Path(syn::TypePath {
+ qself: None,
+ ref path,
+ }) => {
+ let last = path.segments.last().unwrap();
+ let string = last.ident.to_string();
+
+ match string.as_str() {
+ "Option" => {
+ let nested = introspect_type(first_arg(&last.arguments), items, tokens);
+ types::Type::Option(Box::new(nested))
+ }
+ "Punctuated" => {
+ let nested = introspect_type(first_arg(&last.arguments), items, tokens);
+ let punct = match introspect_type(last_arg(&last.arguments), items, tokens) {
+ types::Type::Token(s) => s,
+ _ => panic!(),
+ };
+
+ types::Type::Punctuated(types::Punctuated {
+ element: Box::new(nested),
+ punct,
+ })
+ }
+ "Vec" => {
+ let nested = introspect_type(first_arg(&last.arguments), items, tokens);
+ types::Type::Vec(Box::new(nested))
+ }
+ "Box" => {
+ let nested = introspect_type(first_arg(&last.arguments), items, tokens);
+ types::Type::Box(Box::new(nested))
+ }
+ "Brace" | "Bracket" | "Paren" | "Group" => types::Type::Group(string),
+ "TokenStream" | "Literal" | "Ident" | "Span" => types::Type::Ext(string),
+ "String" | "u32" | "usize" | "bool" => types::Type::Std(string),
+ "Await" => types::Type::Token("Await".to_string()),
+ _ => {
+ if items.get(&last.ident).is_some() || last.ident == "Reserved" {
+ types::Type::Syn(string)
+ } else {
+ unimplemented!("{}", string);
+ }
+ }
+ }
+ }
+ syn::Type::Tuple(syn::TypeTuple { ref elems, .. }) => {
+ let tys = elems
+ .iter()
+ .map(|ty| introspect_type(&ty, items, tokens))
+ .collect();
+ types::Type::Tuple(tys)
+ }
+ syn::Type::Macro(syn::TypeMacro { ref mac })
+ if mac.path.segments.last().unwrap().ident == "Token" =>
+ {
+ let content = mac.tokens.to_string();
+ let ty = tokens.get(&content).unwrap().to_string();
+
+ types::Type::Token(ty)
+ }
+ _ => panic!("{}", quote!(#item).to_string()),
+ }
+}
+
+fn introspect_features(attrs: &[syn::Attribute]) -> types::Features {
+ let mut ret = types::Features::default();
+
+ for attr in attrs {
+ if !attr.path.is_ident("cfg") {
+ continue;
+ }
+
+ let features = parsing::parse_features.parse2(attr.tokens.clone()).unwrap();
+
+ if ret.any.is_empty() {
+ ret = features;
+ } else if ret.any.len() < features.any.len() {
+ assert!(ret.any.iter().all(|f| features.any.contains(f)));
+ } else {
+ assert!(features.any.iter().all(|f| ret.any.contains(f)));
+ ret = features;
+ }
+ }
+
+ ret
+}
+
+fn is_pub(vis: &syn::Visibility) -> bool {
+ match vis {
+ syn::Visibility::Public(_) => true,
+ _ => false,
+ }
+}
+
+fn first_arg(params: &syn::PathArguments) -> &syn::Type {
+ let data = match *params {
+ syn::PathArguments::AngleBracketed(ref data) => data,
+ _ => panic!("Expected at least 1 type argument here"),
+ };
+
+ match *data
+ .args
+ .first()
+ .expect("Expected at least 1 type argument here")
+ {
+ syn::GenericArgument::Type(ref ty) => ty,
+ _ => panic!("Expected at least 1 type argument here"),
+ }
+}
+
+fn last_arg(params: &syn::PathArguments) -> &syn::Type {
+ let data = match *params {
+ syn::PathArguments::AngleBracketed(ref data) => data,
+ _ => panic!("Expected at least 1 type argument here"),
+ };
+
+ match *data
+ .args
+ .last()
+ .expect("Expected at least 1 type argument here")
+ {
+ syn::GenericArgument::Type(ref ty) => ty,
+ _ => panic!("Expected at least 1 type argument here"),
+ }
+}
+
+mod parsing {
+ use super::{AstItem, TokenLookup};
+
+ use proc_macro2::{TokenStream, TokenTree};
+ use quote::quote;
+ use syn;
+ use syn::parse::{ParseStream, Result};
+ use syn::*;
+ use syn_codegen as types;
+
+ use std::collections::{BTreeMap, BTreeSet};
+
+ fn peek_tag(input: ParseStream, tag: &str) -> bool {
+ let ahead = input.fork();
+ ahead.parse::<Token![#]>().is_ok()
+ && ahead
+ .parse::<Ident>()
+ .map(|ident| ident == tag)
+ .unwrap_or(false)
+ }
+
+ // Parses #full - returns #[cfg(feature = "full")] if it is present, and
+ // nothing otherwise.
+ fn full(input: ParseStream) -> Vec<syn::Attribute> {
+ if peek_tag(input, "full") {
+ input.parse::<Token![#]>().unwrap();
+ input.parse::<Ident>().unwrap();
+ vec![parse_quote!(#[cfg(feature = "full")])]
+ } else {
+ vec![]
+ }
+ }
+
+ fn skip_manual_extra_traits(input: ParseStream) {
+ if peek_tag(input, "manual_extra_traits") || peek_tag(input, "manual_extra_traits_debug") {
+ input.parse::<Token![#]>().unwrap();
+ input.parse::<Ident>().unwrap();
+ }
+ }
+
+ // Parses a simple AstStruct without the `pub struct` prefix.
+ fn ast_struct_inner(input: ParseStream) -> Result<AstItem> {
+ let ident: Ident = input.parse()?;
+ let features = full(input);
+ skip_manual_extra_traits(input);
+ let rest: TokenStream = input.parse()?;
+ Ok(AstItem {
+ ast: syn::parse2(quote! {
+ pub struct #ident #rest
+ })?,
+ features,
+ })
+ }
+
+ pub fn ast_struct(input: ParseStream) -> Result<AstItem> {
+ input.call(Attribute::parse_outer)?;
+ input.parse::<Token![pub]>()?;
+ input.parse::<Token![struct]>()?;
+ let res = input.call(ast_struct_inner)?;
+ Ok(res)
+ }
+
+ fn no_visit(input: ParseStream) -> bool {
+ if peek_tag(input, "no_visit") {
+ input.parse::<Token![#]>().unwrap();
+ input.parse::<Ident>().unwrap();
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn ast_enum(input: ParseStream) -> Result<Option<AstItem>> {
+ input.call(Attribute::parse_outer)?;
+ input.parse::<Token![pub]>()?;
+ input.parse::<Token![enum]>()?;
+ let ident: Ident = input.parse()?;
+ skip_manual_extra_traits(input);
+ let no_visit = no_visit(input);
+ let rest: TokenStream = input.parse()?;
+ Ok(if no_visit {
+ None
+ } else {
+ Some(AstItem {
+ ast: syn::parse2(quote! {
+ pub enum #ident #rest
+ })?,
+ features: vec![],
+ })
+ })
+ }
+
+ // A single variant of an ast_enum_of_structs!
+ struct EosVariant {
+ name: Ident,
+ member: Option<Path>,
+ }
+ fn eos_variant(input: ParseStream) -> Result<EosVariant> {
+ input.call(Attribute::parse_outer)?;
+ let variant: Ident = input.parse()?;
+ let member = if input.peek(token::Paren) {
+ let content;
+ parenthesized!(content in input);
+ let path: Path = content.parse()?;
+ Some(path)
+ } else {
+ None
+ };
+ input.parse::<Token![,]>()?;
+ Ok(EosVariant {
+ name: variant,
+ member,
+ })
+ }
+
+ pub fn ast_enum_of_structs(input: ParseStream) -> Result<AstItem> {
+ input.call(Attribute::parse_outer)?;
+ input.parse::<Token![pub]>()?;
+ input.parse::<Token![enum]>()?;
+ let ident: Ident = input.parse()?;
+ skip_manual_extra_traits(input);
+
+ let content;
+ braced!(content in input);
+ let mut variants = Vec::new();
+ while !content.is_empty() {
+ variants.push(content.call(eos_variant)?);
+ }
+
+ if let Some(ident) = input.parse::<Option<Ident>>()? {
+ assert_eq!(ident, "do_not_generate_to_tokens");
+ }
+
+ let enum_item = {
+ let variants = variants.iter().map(|v| {
+ let name = v.name.clone();
+ match v.member {
+ Some(ref member) => quote!(#name(#member)),
+ None => quote!(#name),
+ }
+ });
+ parse_quote! {
+ pub enum #ident {
+ #(#variants),*
+ }
+ }
+ };
+ Ok(AstItem {
+ ast: enum_item,
+ features: vec![],
+ })
+ }
+
+ mod kw {
+ syn::custom_keyword!(macro_rules);
+ syn::custom_keyword!(Token);
+ }
+
+ pub fn parse_token_macro(input: ParseStream) -> Result<TokenLookup> {
+ input.parse::<TokenTree>()?;
+ input.parse::<Token![=>]>()?;
+
+ let definition;
+ braced!(definition in input);
+ definition.call(Attribute::parse_outer)?;
+ definition.parse::<kw::macro_rules>()?;
+ definition.parse::<Token![!]>()?;
+ definition.parse::<kw::Token>()?;
+
+ let rules;
+ braced!(rules in definition);
+ input.parse::<Token![;]>()?;
+
+ let mut tokens = BTreeMap::new();
+ while !rules.is_empty() {
+ if rules.peek(Token![$]) {
+ rules.parse::<Token![$]>()?;
+ rules.parse::<TokenTree>()?;
+ rules.parse::<Token![*]>()?;
+ tokens.insert("await".to_owned(), "Await".to_owned());
+ } else {
+ let pattern;
+ parenthesized!(pattern in rules);
+ let token = pattern.parse::<TokenStream>()?.to_string();
+ rules.parse::<Token![=>]>()?;
+ let expansion;
+ braced!(expansion in rules);
+ rules.parse::<Token![;]>()?;
+ expansion.parse::<Token![$]>()?;
+ let path: Path = expansion.parse()?;
+ let ty = path.segments.last().unwrap().ident.to_string();
+ tokens.insert(token, ty.to_string());
+ }
+ }
+ Ok(tokens)
+ }
+
+ fn parse_feature(input: ParseStream) -> Result<String> {
+ let i: syn::Ident = input.parse()?;
+ assert_eq!(i, "feature");
+
+ input.parse::<Token![=]>()?;
+ let s = input.parse::<syn::LitStr>()?;
+
+ Ok(s.value())
+ }
+
+ pub fn parse_features(input: ParseStream) -> Result<types::Features> {
+ let mut features = BTreeSet::new();
+
+ let level_1;
+ parenthesized!(level_1 in input);
+
+ let i: syn::Ident = level_1.fork().parse()?;
+
+ if i == "any" {
+ level_1.parse::<syn::Ident>()?;
+
+ let level_2;
+ parenthesized!(level_2 in level_1);
+
+ while !level_2.is_empty() {
+ features.insert(parse_feature(&level_2)?);
+
+ if !level_2.is_empty() {
+ level_2.parse::<Token![,]>()?;
+ }
+ }
+ } else if i == "feature" {
+ features.insert(parse_feature(&level_1)?);
+ assert!(level_1.is_empty());
+ } else {
+ panic!("{:?}", i);
+ }
+
+ assert!(input.is_empty());
+
+ Ok(types::Features { any: features })
+ }
+}
+
+fn get_features(attrs: &[syn::Attribute], base: &[syn::Attribute]) -> Vec<syn::Attribute> {
+ let mut ret = base.to_owned();
+
+ for attr in attrs {
+ if attr.path.is_ident("cfg") {
+ ret.push(attr.clone());
+ }
+ }
+
+ ret
+}
+
+#[derive(Error, Debug)]
+#[error("{path}:{line}:{column}: {error}")]
+struct LoadFileError {
+ path: PathBuf,
+ line: usize,
+ column: usize,
+ error: syn::Error,
+}
+
+fn load_file<P: AsRef<Path>>(
+ name: P,
+ features: &[syn::Attribute],
+ lookup: &mut ItemLookup,
+) -> Result<()> {
+ let error = match do_load_file(&name, features, lookup).err() {
+ None => return Ok(()),
+ Some(error) => error,
+ };
+
+ let error = error.downcast::<syn::Error>()?;
+ let span = error.span().start();
+
+ bail!(LoadFileError {
+ path: name.as_ref().to_owned(),
+ line: span.line,
+ column: span.column + 1,
+ error,
+ })
+}
+
+fn do_load_file<P: AsRef<Path>>(
+ name: P,
+ features: &[syn::Attribute],
+ lookup: &mut ItemLookup,
+) -> Result<()> {
+ let name = name.as_ref();
+ let parent = name.parent().expect("no parent path");
+
+ // Parse the file
+ let src = fs::read_to_string(name)?;
+ let file = syn::parse_file(&src)?;
+
+ // Collect all of the interesting AstItems declared in this file or submodules.
+ 'items: for item in file.items {
+ match item {
+ Item::Mod(item) => {
+ // Don't inspect inline modules.
+ if item.content.is_some() {
+ continue;
+ }
+
+ // We don't want to try to load the generated rust files and
+ // parse them, so we ignore them here.
+ for name in IGNORED_MODS {
+ if item.ident == name {
+ continue 'items;
+ }
+ }
+
+ // Lookup any #[cfg()] attributes on the module and add them to
+ // the feature set.
+ //
+ // The derive module is weird because it is built with either
+ // `full` or `derive` but exported only under `derive`.
+ let features = if item.ident == "derive" {
+ vec![parse_quote!(#[cfg(feature = "derive")])]
+ } else {
+ get_features(&item.attrs, features)
+ };
+
+ // Look up the submodule file, and recursively parse it.
+ // Only handles same-directory .rs file submodules for now.
+ let path = parent.join(&format!("{}.rs", item.ident));
+ load_file(path, &features, lookup)?;
+ }
+ Item::Macro(item) => {
+ // Lookip any #[cfg()] attributes directly on the macro
+ // invocation, and add them to the feature set.
+ let features = get_features(&item.attrs, features);
+
+ // Try to parse the AstItem declaration out of the item.
+ let tts = item.mac.tokens.clone();
+ let found = if item.mac.path.is_ident("ast_struct") {
+ Some(parsing::ast_struct.parse2(tts)?)
+ } else if item.mac.path.is_ident("ast_enum") {
+ parsing::ast_enum.parse2(tts)?
+ } else if item.mac.path.is_ident("ast_enum_of_structs") {
+ Some(parsing::ast_enum_of_structs.parse2(tts)?)
+ } else {
+ continue;
+ };
+
+ // Record our features on the parsed AstItems.
+ for mut item in found {
+ if item.ast.ident != "Reserved" {
+ item.features.extend(features.clone());
+ lookup.insert(item.ast.ident.clone(), item);
+ }
+ }
+ }
+ Item::Struct(item) => {
+ let ident = item.ident;
+ if EXTRA_TYPES.contains(&&ident.to_string()[..]) {
+ lookup.insert(
+ ident.clone(),
+ AstItem {
+ ast: DeriveInput {
+ ident,
+ vis: item.vis,
+ attrs: item.attrs,
+ generics: item.generics,
+ data: Data::Struct(DataStruct {
+ fields: item.fields,
+ struct_token: item.struct_token,
+ semi_token: item.semi_token,
+ }),
+ },
+ features: features.to_owned(),
+ },
+ );
+ }
+ }
+ _ => {}
+ }
+ }
+ Ok(())
+}
+
+fn load_token_file<P: AsRef<Path>>(name: P) -> Result<TokenLookup> {
+ let name = name.as_ref();
+ let src = fs::read_to_string(name)?;
+ let file = syn::parse_file(&src)?;
+ for item in file.items {
+ match item {
+ Item::Macro(item) => {
+ match item.ident {
+ Some(ref i) if i == "export_token_macro" => {}
+ _ => continue,
+ }
+ let tokens = item.mac.parse_body_with(parsing::parse_token_macro)?;
+ return Ok(tokens);
+ }
+ _ => {}
+ }
+ }
+
+ panic!("failed to parse Token macro")
+}
diff --git a/syn/codegen/src/version.rs b/syn/codegen/src/version.rs
new file mode 100644
index 0000000..9374624
--- /dev/null
+++ b/syn/codegen/src/version.rs
@@ -0,0 +1,24 @@
+use anyhow::Result;
+use semver::Version;
+use serde::Deserialize;
+
+use std::fs;
+use std::path::Path;
+
+pub fn get() -> Result<Version> {
+ let codegen_root = Path::new(env!("CARGO_MANIFEST_DIR"));
+ let syn_cargo_toml = codegen_root.join("../Cargo.toml");
+ let manifest = fs::read_to_string(syn_cargo_toml)?;
+ let parsed: Manifest = toml::from_str(&manifest)?;
+ Ok(parsed.package.version)
+}
+
+#[derive(Debug, Deserialize)]
+struct Manifest {
+ package: Package,
+}
+
+#[derive(Debug, Deserialize)]
+struct Package {
+ version: Version,
+}
diff --git a/syn/codegen/src/visit.rs b/syn/codegen/src/visit.rs
new file mode 100644
index 0000000..41bc9e9
--- /dev/null
+++ b/syn/codegen/src/visit.rs
@@ -0,0 +1,265 @@
+use crate::operand::{Borrowed, Operand, Owned};
+use crate::{file, full, gen};
+use anyhow::Result;
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::quote;
+use syn::Index;
+use syn_codegen::{Data, Definitions, Features, Node, Type};
+
+const VISIT_SRC: &str = "../src/gen/visit.rs";
+
+fn simple_visit(item: &str, name: &Operand) -> TokenStream {
+ let ident = gen::under_name(item);
+ let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
+ let name = name.ref_tokens();
+ quote! {
+ v.#method(#name)
+ }
+}
+
+fn noop_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ skip!(#name)
+ }
+}
+
+fn visit(
+ ty: &Type,
+ features: &Features,
+ defs: &Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ match ty {
+ Type::Box(t) => {
+ let name = name.owned_tokens();
+ visit(t, features, defs, &Owned(quote!(*#name)))
+ }
+ Type::Vec(t) => {
+ let operand = Borrowed(quote!(it));
+ let val = visit(t, features, defs, &operand)?;
+ let name = name.ref_tokens();
+ Some(quote! {
+ for it in #name {
+ #val
+ }
+ })
+ }
+ Type::Punctuated(p) => {
+ let operand = Borrowed(quote!(it));
+ let val = visit(&p.element, features, defs, &operand)?;
+ let name = name.ref_tokens();
+ Some(quote! {
+ for el in Punctuated::pairs(#name) {
+ let (it, p) = el.into_tuple();
+ #val;
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ })
+ }
+ Type::Option(t) => {
+ let it = Borrowed(quote!(it));
+ let val = visit(t, features, defs, &it)?;
+ let name = name.owned_tokens();
+ Some(quote! {
+ if let Some(it) = &#name {
+ #val
+ }
+ })
+ }
+ Type::Tuple(t) => {
+ let mut code = TokenStream::new();
+ for (i, elem) in t.iter().enumerate() {
+ let name = name.tokens();
+ let i = Index::from(i);
+ let it = Owned(quote!((#name).#i));
+ let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
+ code.extend(val);
+ code.extend(quote!(;));
+ }
+ Some(code)
+ }
+ Type::Token(t) => {
+ let name = name.tokens();
+ let repr = &defs.tokens[t];
+ let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+ let spans = if is_keyword {
+ quote!(span)
+ } else {
+ quote!(spans)
+ };
+ Some(quote! {
+ tokens_helper(v, &#name.#spans)
+ })
+ }
+ Type::Group(_) => {
+ let name = name.tokens();
+ Some(quote! {
+ tokens_helper(v, &#name.span)
+ })
+ }
+ Type::Syn(t) => {
+ fn requires_full(features: &Features) -> bool {
+ features.any.contains("full") && features.any.len() == 1
+ }
+ let mut res = simple_visit(t, name);
+ let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
+ if requires_full(&target.features) && !requires_full(features) {
+ res = quote!(full!(#res));
+ }
+ Some(res)
+ }
+ Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+ Type::Ext(_) | Type::Std(_) => None,
+ }
+}
+
+fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) {
+ let under_name = gen::under_name(&s.ident);
+ let ty = Ident::new(&s.ident, Span::call_site());
+ let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
+
+ let mut visit_impl = TokenStream::new();
+
+ match &s.data {
+ Data::Enum(variants) => {
+ let mut visit_variants = TokenStream::new();
+
+ for (variant, fields) in variants {
+ let variant_ident = Ident::new(variant, Span::call_site());
+
+ if fields.is_empty() {
+ visit_variants.extend(quote! {
+ #ty::#variant_ident => {}
+ });
+ } else {
+ let mut bind_visit_fields = TokenStream::new();
+ let mut visit_fields = TokenStream::new();
+
+ for (idx, ty) in fields.iter().enumerate() {
+ let name = format!("_binding_{}", idx);
+ let binding = Ident::new(&name, Span::call_site());
+
+ bind_visit_fields.extend(quote! {
+ #binding,
+ });
+
+ let borrowed_binding = Borrowed(quote!(#binding));
+
+ visit_fields.extend(
+ visit(ty, &s.features, defs, &borrowed_binding)
+ .unwrap_or_else(|| noop_visit(&borrowed_binding)),
+ );
+
+ visit_fields.extend(quote!(;));
+ }
+
+ visit_variants.extend(quote! {
+ #ty::#variant_ident(#bind_visit_fields) => {
+ #visit_fields
+ }
+ });
+ }
+ }
+
+ let nonexhaustive = if s.exhaustive {
+ None
+ } else {
+ Some(quote!(_ => unreachable!()))
+ };
+
+ visit_impl.extend(quote! {
+ match node {
+ #visit_variants
+ #nonexhaustive
+ }
+ });
+ }
+ Data::Struct(fields) => {
+ for (field, ty) in fields {
+ if let Type::Syn(ty) = ty {
+ if ty == "Reserved" {
+ continue;
+ }
+ }
+
+ let id = Ident::new(&field, Span::call_site());
+ let ref_toks = Owned(quote!(node.#id));
+ let visit_field = visit(&ty, &s.features, defs, &ref_toks)
+ .unwrap_or_else(|| noop_visit(&ref_toks));
+ visit_impl.extend(quote! {
+ #visit_field;
+ });
+ }
+ }
+ Data::Private => {
+ if ty == "Ident" {
+ visit_impl.extend(quote! {
+ v.visit_span(&node.span());
+ });
+ }
+ }
+ }
+
+ let ast_lifetime = if s.ident == "Span" {
+ None
+ } else {
+ Some(quote!('ast))
+ };
+
+ traits.extend(quote! {
+ fn #visit_fn(&mut self, i: &#ast_lifetime #ty) {
+ #visit_fn(self, i)
+ }
+ });
+
+ impls.extend(quote! {
+ pub fn #visit_fn<'ast, V>(v: &mut V, node: &#ast_lifetime #ty)
+ where
+ V: Visit<'ast> + ?Sized,
+ {
+ #visit_impl
+ }
+ });
+}
+
+pub fn generate(defs: &Definitions) -> Result<()> {
+ let (traits, impls) = gen::traverse(defs, node);
+ let full_macro = full::get_macro();
+ file::write(
+ VISIT_SRC,
+ quote! {
+ #![allow(unused_variables)]
+
+ use crate::*;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use crate::punctuated::Punctuated;
+ use proc_macro2::Span;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use crate::gen::helper::visit::*;
+
+ #full_macro
+
+ #[cfg(any(feature = "full", feature = "derive"))]
+ macro_rules! skip {
+ ($($tt:tt)*) => {};
+ }
+
+ /// Syntax tree traversal to walk a shared borrow of a syntax tree.
+ ///
+ /// See the [module documentation] for details.
+ ///
+ /// [module documentation]: self
+ ///
+ /// *This trait is available if Syn is built with the `"visit"` feature.*
+ pub trait Visit<'ast> {
+ #traits
+ }
+
+ #impls
+ },
+ )?;
+ Ok(())
+}
diff --git a/syn/codegen/src/visit_mut.rs b/syn/codegen/src/visit_mut.rs
new file mode 100644
index 0000000..71e56b3
--- /dev/null
+++ b/syn/codegen/src/visit_mut.rs
@@ -0,0 +1,262 @@
+use crate::operand::{Borrowed, Operand, Owned};
+use crate::{file, full, gen};
+use anyhow::Result;
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::quote;
+use syn::Index;
+use syn_codegen::{Data, Definitions, Features, Node, Type};
+
+const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
+
+fn simple_visit(item: &str, name: &Operand) -> TokenStream {
+ let ident = gen::under_name(item);
+ let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
+ let name = name.ref_mut_tokens();
+ quote! {
+ v.#method(#name)
+ }
+}
+
+fn noop_visit(name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ quote! {
+ skip!(#name)
+ }
+}
+
+fn visit(
+ ty: &Type,
+ features: &Features,
+ defs: &Definitions,
+ name: &Operand,
+) -> Option<TokenStream> {
+ match ty {
+ Type::Box(t) => {
+ let name = name.owned_tokens();
+ visit(t, features, defs, &Owned(quote!(*#name)))
+ }
+ Type::Vec(t) => {
+ let operand = Borrowed(quote!(it));
+ let val = visit(t, features, defs, &operand)?;
+ let name = name.ref_mut_tokens();
+ Some(quote! {
+ for it in #name {
+ #val
+ }
+ })
+ }
+ Type::Punctuated(p) => {
+ let operand = Borrowed(quote!(it));
+ let val = visit(&p.element, features, defs, &operand)?;
+ let name = name.ref_mut_tokens();
+ Some(quote! {
+ for el in Punctuated::pairs_mut(#name) {
+ let (it, p) = el.into_tuple();
+ #val;
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ })
+ }
+ Type::Option(t) => {
+ let it = Borrowed(quote!(it));
+ let val = visit(t, features, defs, &it)?;
+ let name = name.owned_tokens();
+ Some(quote! {
+ if let Some(it) = &mut #name {
+ #val
+ }
+ })
+ }
+ Type::Tuple(t) => {
+ let mut code = TokenStream::new();
+ for (i, elem) in t.iter().enumerate() {
+ let name = name.tokens();
+ let i = Index::from(i);
+ let it = Owned(quote!((#name).#i));
+ let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
+ code.extend(val);
+ code.extend(quote!(;));
+ }
+ Some(code)
+ }
+ Type::Token(t) => {
+ let name = name.tokens();
+ let repr = &defs.tokens[t];
+ let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+ let spans = if is_keyword {
+ quote!(span)
+ } else {
+ quote!(spans)
+ };
+ Some(quote! {
+ tokens_helper(v, &mut #name.#spans)
+ })
+ }
+ Type::Group(_) => {
+ let name = name.tokens();
+ Some(quote! {
+ tokens_helper(v, &mut #name.span)
+ })
+ }
+ Type::Syn(t) => {
+ fn requires_full(features: &Features) -> bool {
+ features.any.contains("full") && features.any.len() == 1
+ }
+ let mut res = simple_visit(t, name);
+ let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
+ if requires_full(&target.features) && !requires_full(features) {
+ res = quote!(full!(#res));
+ }
+ Some(res)
+ }
+ Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+ Type::Ext(_) | Type::Std(_) => None,
+ }
+}
+
+fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) {
+ let under_name = gen::under_name(&s.ident);
+ let ty = Ident::new(&s.ident, Span::call_site());
+ let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
+
+ let mut visit_mut_impl = TokenStream::new();
+
+ match &s.data {
+ Data::Enum(variants) => {
+ let mut visit_mut_variants = TokenStream::new();
+
+ for (variant, fields) in variants {
+ let variant_ident = Ident::new(variant, Span::call_site());
+
+ if fields.is_empty() {
+ visit_mut_variants.extend(quote! {
+ #ty::#variant_ident => {}
+ });
+ } else {
+ let mut bind_visit_mut_fields = TokenStream::new();
+ let mut visit_mut_fields = TokenStream::new();
+
+ for (idx, ty) in fields.iter().enumerate() {
+ let name = format!("_binding_{}", idx);
+ let binding = Ident::new(&name, Span::call_site());
+
+ bind_visit_mut_fields.extend(quote! {
+ #binding,
+ });
+
+ let borrowed_binding = Borrowed(quote!(#binding));
+
+ visit_mut_fields.extend(
+ visit(ty, &s.features, defs, &borrowed_binding)
+ .unwrap_or_else(|| noop_visit(&borrowed_binding)),
+ );
+
+ visit_mut_fields.extend(quote!(;));
+ }
+
+ visit_mut_variants.extend(quote! {
+ #ty::#variant_ident(#bind_visit_mut_fields) => {
+ #visit_mut_fields
+ }
+ });
+ }
+ }
+
+ let nonexhaustive = if s.exhaustive {
+ None
+ } else {
+ Some(quote!(_ => unreachable!()))
+ };
+
+ visit_mut_impl.extend(quote! {
+ match node {
+ #visit_mut_variants
+ #nonexhaustive
+ }
+ });
+ }
+ Data::Struct(fields) => {
+ for (field, ty) in fields {
+ if let Type::Syn(ty) = ty {
+ if ty == "Reserved" {
+ continue;
+ }
+ }
+
+ let id = Ident::new(&field, Span::call_site());
+ let ref_toks = Owned(quote!(node.#id));
+ let visit_mut_field = visit(&ty, &s.features, defs, &ref_toks)
+ .unwrap_or_else(|| noop_visit(&ref_toks));
+ visit_mut_impl.extend(quote! {
+ #visit_mut_field;
+ });
+ }
+ }
+ Data::Private => {
+ if ty == "Ident" {
+ visit_mut_impl.extend(quote! {
+ let mut span = node.span();
+ v.visit_span_mut(&mut span);
+ node.set_span(span);
+ });
+ }
+ }
+ }
+
+ traits.extend(quote! {
+ fn #visit_mut_fn(&mut self, i: &mut #ty) {
+ #visit_mut_fn(self, i)
+ }
+ });
+
+ impls.extend(quote! {
+ pub fn #visit_mut_fn<V>(v: &mut V, node: &mut #ty)
+ where
+ V: VisitMut + ?Sized,
+ {
+ #visit_mut_impl
+ }
+ });
+}
+
+pub fn generate(defs: &Definitions) -> Result<()> {
+ let (traits, impls) = gen::traverse(defs, node);
+ let full_macro = full::get_macro();
+ file::write(
+ VISIT_MUT_SRC,
+ quote! {
+ #![allow(unused_variables)]
+
+ use crate::*;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use crate::punctuated::Punctuated;
+ use proc_macro2::Span;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use crate::gen::helper::visit_mut::*;
+
+ #full_macro
+
+ #[cfg(any(feature = "full", feature = "derive"))]
+ macro_rules! skip {
+ ($($tt:tt)*) => {};
+ }
+
+ /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
+ /// place.
+ ///
+ /// See the [module documentation] for details.
+ ///
+ /// [module documentation]: self
+ ///
+ /// *This trait is available if Syn is built with the `"visit-mut"` feature.*
+ pub trait VisitMut {
+ #traits
+ }
+
+ #impls
+ },
+ )?;
+ Ok(())
+}
diff --git a/syn/dev/Cargo.toml b/syn/dev/Cargo.toml
new file mode 100644
index 0000000..79486c1
--- /dev/null
+++ b/syn/dev/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "syn-dev"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[lib]
+path = "parse.rs"
+proc-macro = true
+
+[[bin]]
+path = "main.rs"
+name = "syn-dev"
+
+[dependencies]
+quote = "1.0"
+
+[dependencies.syn]
+path = ".."
+default-features = false
+features = ["parsing", "full", "extra-traits", "proc-macro"]
diff --git a/syn/dev/README.md b/syn/dev/README.md
new file mode 100644
index 0000000..91b9846
--- /dev/null
+++ b/syn/dev/README.md
@@ -0,0 +1,6 @@
+A little project skeleton for troubleshooting Syn's parsers during development,
+especially when adding support for new Rust syntax.
+
+Place a sample of the syntax you are working on into main.rs and then run `cargo
+check` to try parsing it, revealing the resulting syntax tree or else showing
+the position and error message if the input fails to parse.
diff --git a/syn/dev/main.rs b/syn/dev/main.rs
new file mode 100644
index 0000000..eb67546
--- /dev/null
+++ b/syn/dev/main.rs
@@ -0,0 +1,4 @@
+syn_dev::r#mod! {
+ // Write Rust code here and run `cargo check` to have Syn parse it.
+
+}
diff --git a/syn/dev/parse.rs b/syn/dev/parse.rs
new file mode 100644
index 0000000..2a92550
--- /dev/null
+++ b/syn/dev/parse.rs
@@ -0,0 +1,18 @@
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::File;
+
+#[proc_macro]
+pub fn r#mod(input: TokenStream) -> TokenStream {
+ let compile_error = syn::parse::<File>(input)
+ .map(|file| println!("{:#?}", file))
+ .map_err(|err| err.to_compile_error())
+ .err();
+
+ TokenStream::from(quote! {
+ #compile_error
+ fn main() {}
+ })
+}
diff --git a/syn/examples/README.md b/syn/examples/README.md
new file mode 100644
index 0000000..fdd69d6
--- /dev/null
+++ b/syn/examples/README.md
@@ -0,0 +1,19 @@
+### [`dump-syntax`](dump-syntax)
+
+Little utility to parse a Rust source file into a `syn::File` and print out a
+debug representation of the syntax tree.
+
+### [`heapsize`](heapsize)
+
+An example implementation of a derive macro that generates trait impls.
+
+### [`lazy-static`](lazy-static)
+
+An example of parsing a custom syntax within a `functionlike!(...)` procedural
+macro. Demonstrates how to trigger custom warnings and error messages on
+individual tokens of the input.
+
+### [`trace-var`](trace-var)
+
+An attribute procedural macro that uses a syntax tree traversal to transform
+certain syntax tree nodes in a function body.
diff --git a/syn/examples/dump-syntax/Cargo.toml b/syn/examples/dump-syntax/Cargo.toml
new file mode 100644
index 0000000..0bc9f62
--- /dev/null
+++ b/syn/examples/dump-syntax/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "dump-syntax"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+colored = "1.7"
+proc-macro2 = { version = "1.0", features = ["span-locations"] }
+
+[dependencies.syn]
+path = "../.."
+default-features = false
+features = ["parsing", "full", "extra-traits"]
+
+[workspace]
diff --git a/syn/examples/dump-syntax/README.md b/syn/examples/dump-syntax/README.md
new file mode 100644
index 0000000..37c84d8
--- /dev/null
+++ b/syn/examples/dump-syntax/README.md
@@ -0,0 +1,28 @@
+Parse a Rust source file into a `syn::File` and print out a debug representation
+of the syntax tree.
+
+Use the following command from this directory to test this program by running it
+on its own source code:
+
+```
+cargo run -- src/main.rs
+```
+
+The output will begin with:
+
+```
+File {
+ shebang: None,
+ attrs: [
+ Attribute {
+ pound_token: Pound,
+ style: Inner(
+ Bang
+ ),
+ bracket_token: Bracket,
+ path: Path {
+ leading_colon: None,
+ segments: [
+ ...
+}
+```
diff --git a/syn/examples/dump-syntax/src/main.rs b/syn/examples/dump-syntax/src/main.rs
new file mode 100644
index 0000000..240b7a2
--- /dev/null
+++ b/syn/examples/dump-syntax/src/main.rs
@@ -0,0 +1,149 @@
+//! Parse a Rust source file into a `syn::File` and print out a debug
+//! representation of the syntax tree.
+//!
+//! Use the following command from this directory to test this program by
+//! running it on its own source code:
+//!
+//! cargo run -- src/main.rs
+//!
+//! The output will begin with:
+//!
+//! File {
+//! shebang: None,
+//! attrs: [
+//! Attribute {
+//! pound_token: Pound,
+//! style: Inner(
+//! ...
+//! }
+
+use std::borrow::Cow;
+use std::env;
+use std::ffi::OsStr;
+use std::fmt::{self, Display};
+use std::fs;
+use std::io::{self, Write};
+use std::path::{Path, PathBuf};
+use std::process;
+
+use colored::Colorize;
+
+enum Error {
+ IncorrectUsage,
+ ReadFile(io::Error),
+ ParseFile {
+ error: syn::Error,
+ filepath: PathBuf,
+ source_code: String,
+ },
+}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::Error::*;
+
+ match self {
+ IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
+ ReadFile(error) => write!(f, "Unable to read file: {}", error),
+ ParseFile {
+ error,
+ filepath,
+ source_code,
+ } => render_location(f, error, filepath, source_code),
+ }
+ }
+}
+
+fn main() {
+ if let Err(error) = try_main() {
+ let _ = writeln!(io::stderr(), "{}", error);
+ process::exit(1);
+ }
+}
+
+fn try_main() -> Result<(), Error> {
+ let mut args = env::args_os();
+ let _ = args.next(); // executable name
+
+ let filepath = match (args.next(), args.next()) {
+ (Some(arg), None) => PathBuf::from(arg),
+ _ => return Err(Error::IncorrectUsage),
+ };
+
+ let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?;
+ let syntax = syn::parse_file(&code).map_err({
+ |error| Error::ParseFile {
+ error,
+ filepath,
+ source_code: code,
+ }
+ })?;
+ println!("{:#?}", syntax);
+
+ Ok(())
+}
+
+// Render a rustc-style error message, including colors.
+//
+// error: Syn unable to parse file
+// --> main.rs:40:17
+// |
+// 40 | fn fmt(&self formatter: &mut fmt::Formatter) -> fmt::Result {
+// | ^^^^^^^^^ expected `,`
+//
+fn render_location(
+ formatter: &mut fmt::Formatter,
+ err: &syn::Error,
+ filepath: &Path,
+ code: &str,
+) -> fmt::Result {
+ let start = err.span().start();
+ let mut end = err.span().end();
+
+ if start.line == end.line && start.column == end.column {
+ return render_fallback(formatter, err);
+ }
+
+ let code_line = match code.lines().nth(start.line - 1) {
+ Some(line) => line,
+ None => return render_fallback(formatter, err),
+ };
+
+ if end.line > start.line {
+ end.line = start.line;
+ end.column = code_line.len();
+ }
+
+ let filename = filepath
+ .file_name()
+ .map(OsStr::to_string_lossy)
+ .unwrap_or(Cow::Borrowed("main.rs"));
+
+ write!(
+ formatter,
+ "\n\
+ {error}{header}\n\
+ {indent}{arrow} {filename}:{linenum}:{colnum}\n\
+ {indent} {pipe}\n\
+ {label} {pipe} {code}\n\
+ {indent} {pipe} {offset}{underline} {message}\n\
+ ",
+ error = "error".red().bold(),
+ header = ": Syn unable to parse file".bold(),
+ indent = " ".repeat(start.line.to_string().len()),
+ arrow = "-->".blue().bold(),
+ filename = filename,
+ linenum = start.line,
+ colnum = start.column,
+ pipe = "|".blue().bold(),
+ label = start.line.to_string().blue().bold(),
+ code = code_line.trim_end(),
+ offset = " ".repeat(start.column),
+ underline = "^".repeat(end.column - start.column).red().bold(),
+ message = err.to_string().red(),
+ )
+}
+
+fn render_fallback(formatter: &mut fmt::Formatter, err: &syn::Error) -> fmt::Result {
+ write!(formatter, "Unable to parse file: {}", err)
+}
diff --git a/syn/examples/heapsize/Cargo.toml b/syn/examples/heapsize/Cargo.toml
new file mode 100644
index 0000000..9b19214
--- /dev/null
+++ b/syn/examples/heapsize/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["example", "heapsize", "heapsize_derive"]
diff --git a/syn/examples/heapsize/README.md b/syn/examples/heapsize/README.md
new file mode 100644
index 0000000..e789559
--- /dev/null
+++ b/syn/examples/heapsize/README.md
@@ -0,0 +1,72 @@
+A derive macro that generates trait impls.
+
+- [`heapsize/src/lib.rs`](heapsize/src/lib.rs)
+- [`heapsize_derive/src/lib.rs`](heapsize_derive/src/lib.rs)
+- [`example/src/main.rs`](example/src/main.rs)
+
+We are deriving the `HeapSize` trait which computes an estimate of the amount of
+heap memory owned by a value.
+
+```rust
+pub trait HeapSize {
+ /// Total number of bytes of heap memory owned by `self`.
+ fn heap_size_of_children(&self) -> usize;
+}
+```
+
+The derive macro allows users to write `#[derive(HeapSize)]` on data structures
+in their program.
+
+```rust
+#[derive(HeapSize)]
+struct Demo<'a, T: ?Sized> {
+ a: Box<T>,
+ b: u8,
+ c: &'a str,
+ d: String,
+}
+```
+
+The trait impl generated by the derive macro here would look like:
+
+```rust
+impl<'a, T: ?Sized + heapsize::HeapSize> heapsize::HeapSize for Demo<'a, T> {
+ fn heap_size_of_children(&self) -> usize {
+ 0 + heapsize::HeapSize::heap_size_of_children(&self.a)
+ + heapsize::HeapSize::heap_size_of_children(&self.b)
+ + heapsize::HeapSize::heap_size_of_children(&self.c)
+ + heapsize::HeapSize::heap_size_of_children(&self.d)
+ }
+}
+```
+
+The implementation of `heapsize_derive` demonstrates some attention to "spans"
+of error messages. For each subexpression in the generated code we apply the
+span of the input fragment under which we would want to trigger a compiler error
+if the subexpression fails to compile. In this example, each recursive call to
+`heap_size_of_children` is associated with the span of the corresponding struct
+field. Thus we get errors in the right place if any of the field types do not
+implement the `HeapSize` trait.
+
+```
+error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
+ --> src/main.rs:7:5
+ |
+7 | bad: std::thread::Thread,
+ | ^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
+```
+
+Some unstable APIs in the `proc-macro2` crate let us improve this further by
+joining together the span of the field name and the field type. There is no
+difference in our code &mdash; everything is as shown in this directory &mdash;
+but building the example crate with `cargo build` shows errors like the one
+above and building with `RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build`
+is able to show errors like the following.
+
+```
+error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
+ --> src/main.rs:7:5
+ |
+7 | bad: std::thread::Thread,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
+```
diff --git a/syn/examples/heapsize/example/Cargo.toml b/syn/examples/heapsize/example/Cargo.toml
new file mode 100644
index 0000000..85c7699
--- /dev/null
+++ b/syn/examples/heapsize/example/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "heapsize_example"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+heapsize = { path = "../heapsize" }
diff --git a/syn/examples/heapsize/example/src/main.rs b/syn/examples/heapsize/example/src/main.rs
new file mode 100644
index 0000000..9332b11
--- /dev/null
+++ b/syn/examples/heapsize/example/src/main.rs
@@ -0,0 +1,28 @@
+use heapsize::HeapSize;
+
+#[derive(HeapSize)]
+struct Demo<'a, T: ?Sized> {
+ a: Box<T>,
+ b: u8,
+ c: &'a str,
+ d: String,
+}
+
+fn main() {
+ let demo = Demo {
+ a: b"bytestring".to_vec().into_boxed_slice(),
+ b: 255,
+ c: "&'static str",
+ d: "String".to_owned(),
+ };
+
+ // 10 + 0 + 0 + 6 = 16
+ println!(
+ "heap size = {} + {} + {} + {} = {}",
+ demo.a.heap_size_of_children(),
+ demo.b.heap_size_of_children(),
+ demo.c.heap_size_of_children(),
+ demo.d.heap_size_of_children(),
+ demo.heap_size_of_children()
+ );
+}
diff --git a/syn/examples/heapsize/heapsize/Cargo.toml b/syn/examples/heapsize/heapsize/Cargo.toml
new file mode 100644
index 0000000..27bb954
--- /dev/null
+++ b/syn/examples/heapsize/heapsize/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "heapsize"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+heapsize_derive = { path = "../heapsize_derive" }
diff --git a/syn/examples/heapsize/heapsize/src/lib.rs b/syn/examples/heapsize/heapsize/src/lib.rs
new file mode 100644
index 0000000..30bb6d6
--- /dev/null
+++ b/syn/examples/heapsize/heapsize/src/lib.rs
@@ -0,0 +1,64 @@
+use std::mem;
+
+pub use heapsize_derive::*;
+
+pub trait HeapSize {
+ /// Total number of bytes of heap memory owned by `self`.
+ ///
+ /// Does not include the size of `self` itself, which may or may not be on
+ /// the heap. Includes only children of `self`, meaning things pointed to by
+ /// `self`.
+ fn heap_size_of_children(&self) -> usize;
+}
+
+//
+// In a real version of this library there would be lots more impls here, but
+// here are some interesting ones.
+//
+
+impl HeapSize for u8 {
+ /// A `u8` does not own any heap memory.
+ fn heap_size_of_children(&self) -> usize {
+ 0
+ }
+}
+
+impl HeapSize for String {
+ /// A `String` owns enough heap memory to hold its reserved capacity.
+ fn heap_size_of_children(&self) -> usize {
+ self.capacity()
+ }
+}
+
+impl<T> HeapSize for Box<T>
+where
+ T: ?Sized + HeapSize,
+{
+ /// A `Box` owns however much heap memory was allocated to hold the value of
+ /// type `T` that we placed on the heap, plus transitively however much `T`
+ /// itself owns.
+ fn heap_size_of_children(&self) -> usize {
+ mem::size_of_val(&**self) + (**self).heap_size_of_children()
+ }
+}
+
+impl<T> HeapSize for [T]
+where
+ T: HeapSize,
+{
+ /// Sum of heap memory owned by each element of a dynamically sized slice of
+ /// `T`.
+ fn heap_size_of_children(&self) -> usize {
+ self.iter().map(HeapSize::heap_size_of_children).sum()
+ }
+}
+
+impl<'a, T> HeapSize for &'a T
+where
+ T: ?Sized,
+{
+ /// A shared reference does not own heap memory.
+ fn heap_size_of_children(&self) -> usize {
+ 0
+ }
+}
diff --git a/syn/examples/heapsize/heapsize_derive/Cargo.toml b/syn/examples/heapsize/heapsize_derive/Cargo.toml
new file mode 100644
index 0000000..f4357b9
--- /dev/null
+++ b/syn/examples/heapsize/heapsize_derive/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "heapsize_derive"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { path = "../../.." }
diff --git a/syn/examples/heapsize/heapsize_derive/src/lib.rs b/syn/examples/heapsize/heapsize_derive/src/lib.rs
new file mode 100644
index 0000000..9176b29
--- /dev/null
+++ b/syn/examples/heapsize/heapsize_derive/src/lib.rs
@@ -0,0 +1,96 @@
+extern crate proc_macro;
+
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned};
+use syn::spanned::Spanned;
+use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Fields, GenericParam, Generics, Index};
+
+#[proc_macro_derive(HeapSize)]
+pub fn derive_heap_size(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ // Parse the input tokens into a syntax tree.
+ let input = parse_macro_input!(input as DeriveInput);
+
+ // Used in the quasi-quotation below as `#name`.
+ let name = input.ident;
+
+ // Add a bound `T: HeapSize` to every type parameter T.
+ let generics = add_trait_bounds(input.generics);
+ let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+
+ // Generate an expression to sum up the heap size of each field.
+ let sum = heap_size_sum(&input.data);
+
+ let expanded = quote! {
+ // The generated impl.
+ impl #impl_generics heapsize::HeapSize for #name #ty_generics #where_clause {
+ fn heap_size_of_children(&self) -> usize {
+ #sum
+ }
+ }
+ };
+
+ // Hand the output tokens back to the compiler.
+ proc_macro::TokenStream::from(expanded)
+}
+
+// Add a bound `T: HeapSize` to every type parameter T.
+fn add_trait_bounds(mut generics: Generics) -> Generics {
+ for param in &mut generics.params {
+ if let GenericParam::Type(ref mut type_param) = *param {
+ type_param.bounds.push(parse_quote!(heapsize::HeapSize));
+ }
+ }
+ generics
+}
+
+// Generate an expression to sum up the heap size of each field.
+fn heap_size_sum(data: &Data) -> TokenStream {
+ match *data {
+ Data::Struct(ref data) => {
+ match data.fields {
+ Fields::Named(ref fields) => {
+ // Expands to an expression like
+ //
+ // 0 + self.x.heap_size() + self.y.heap_size() + self.z.heap_size()
+ //
+ // but using fully qualified function call syntax.
+ //
+ // We take some care to use the span of each `syn::Field` as
+ // the span of the corresponding `heap_size_of_children`
+ // call. This way if one of the field types does not
+ // implement `HeapSize` then the compiler's error message
+ // underlines which field it is. An example is shown in the
+ // readme of the parent directory.
+ let recurse = fields.named.iter().map(|f| {
+ let name = &f.ident;
+ quote_spanned! {f.span()=>
+ heapsize::HeapSize::heap_size_of_children(&self.#name)
+ }
+ });
+ quote! {
+ 0 #(+ #recurse)*
+ }
+ }
+ Fields::Unnamed(ref fields) => {
+ // Expands to an expression like
+ //
+ // 0 + self.0.heap_size() + self.1.heap_size() + self.2.heap_size()
+ let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
+ let index = Index::from(i);
+ quote_spanned! {f.span()=>
+ heapsize::HeapSize::heap_size_of_children(&self.#index)
+ }
+ });
+ quote! {
+ 0 #(+ #recurse)*
+ }
+ }
+ Fields::Unit => {
+ // Unit structs cannot own more than 0 bytes of heap memory.
+ quote!(0)
+ }
+ }
+ }
+ Data::Enum(_) | Data::Union(_) => unimplemented!(),
+ }
+}
diff --git a/syn/examples/lazy-static/Cargo.toml b/syn/examples/lazy-static/Cargo.toml
new file mode 100644
index 0000000..586e547
--- /dev/null
+++ b/syn/examples/lazy-static/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["example", "lazy-static"]
diff --git a/syn/examples/lazy-static/README.md b/syn/examples/lazy-static/README.md
new file mode 100644
index 0000000..bc64585
--- /dev/null
+++ b/syn/examples/lazy-static/README.md
@@ -0,0 +1,42 @@
+An example of parsing a custom syntax within a `functionlike!(...)` procedural
+macro. Demonstrates how to trigger custom warnings and error messages on
+individual tokens of the input.
+
+- [`lazy-static/src/lib.rs`](lazy-static/src/lib.rs)
+- [`example/src/main.rs`](example/src/main.rs)
+
+The library implements a `lazy_static!` macro similar to the one from the real
+[`lazy_static`](https://docs.rs/lazy_static/1.0.0/lazy_static/) crate on
+crates.io.
+
+```rust
+lazy_static! {
+ static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
+}
+```
+
+Compile and run the example by doing `cargo run` in the directory of the
+`example` crate.
+
+The implementation shows how to trigger custom warnings and error messages on
+the macro input. For example if you try adding an uncreatively named `FOO` lazy
+static, the macro will scold you with the following warning.
+
+```
+warning: come on, pick a more creative name
+ --> src/main.rs:10:16
+ |
+10 | static ref FOO: String = "lazy_static".to_owned();
+ | ^^^
+```
+
+And if you try to lazily initialize `() = ()`, the macro will outright refuse to
+compile it for you.
+
+```
+error: I can't think of a legitimate use for lazily initializing the value `()`
+ --> src/main.rs:10:27
+ |
+10 | static ref UNIT: () = ();
+ | ^^
+```
diff --git a/syn/examples/lazy-static/example/Cargo.toml b/syn/examples/lazy-static/example/Cargo.toml
new file mode 100644
index 0000000..716b08c
--- /dev/null
+++ b/syn/examples/lazy-static/example/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "example"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+lazy_static = { path = "../lazy-static" }
+regex = "0.2"
diff --git a/syn/examples/lazy-static/example/src/main.rs b/syn/examples/lazy-static/example/src/main.rs
new file mode 100644
index 0000000..c4f64af
--- /dev/null
+++ b/syn/examples/lazy-static/example/src/main.rs
@@ -0,0 +1,20 @@
+use lazy_static::lazy_static;
+use regex::Regex;
+
+lazy_static! {
+ static ref USERNAME: Regex = {
+ println!("Compiling username regex...");
+ Regex::new("^[a-z0-9_-]{3,16}$").unwrap()
+ };
+}
+
+fn main() {
+ println!("Let's validate some usernames.");
+ validate("fergie");
+ validate("will.i.am");
+}
+
+fn validate(name: &str) {
+ // The USERNAME regex is compiled lazily the first time its value is accessed.
+ println!("is_match({:?}): {}", name, USERNAME.is_match(name));
+}
diff --git a/syn/examples/lazy-static/lazy-static/Cargo.toml b/syn/examples/lazy-static/lazy-static/Cargo.toml
new file mode 100644
index 0000000..bf65787
--- /dev/null
+++ b/syn/examples/lazy-static/lazy-static/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "lazy_static"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = { version = "1.0", features = ["nightly"] }
+quote = "1.0"
+syn = { path = "../../../", features = ["full"] }
diff --git a/syn/examples/lazy-static/lazy-static/src/lib.rs b/syn/examples/lazy-static/lazy-static/src/lib.rs
new file mode 100644
index 0000000..254ca72
--- /dev/null
+++ b/syn/examples/lazy-static/lazy-static/src/lib.rs
@@ -0,0 +1,143 @@
+#![recursion_limit = "128"]
+#![feature(proc_macro_diagnostic)]
+
+extern crate proc_macro;
+use self::proc_macro::TokenStream;
+
+use quote::{quote, quote_spanned};
+use syn::parse::{Parse, ParseStream, Result};
+use syn::spanned::Spanned;
+use syn::{parse_macro_input, Expr, Ident, Token, Type, Visibility};
+
+/// Parses the following syntax, which aligns with the input of the real
+/// `lazy_static` crate.
+///
+/// lazy_static! {
+/// $VISIBILITY static ref $NAME: $TYPE = $EXPR;
+/// }
+///
+/// For example:
+///
+/// lazy_static! {
+/// static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
+/// }
+struct LazyStatic {
+ visibility: Visibility,
+ name: Ident,
+ ty: Type,
+ init: Expr,
+}
+
+impl Parse for LazyStatic {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let visibility: Visibility = input.parse()?;
+ input.parse::<Token![static]>()?;
+ input.parse::<Token![ref]>()?;
+ let name: Ident = input.parse()?;
+ input.parse::<Token![:]>()?;
+ let ty: Type = input.parse()?;
+ input.parse::<Token![=]>()?;
+ let init: Expr = input.parse()?;
+ input.parse::<Token![;]>()?;
+ Ok(LazyStatic {
+ visibility,
+ name,
+ ty,
+ init,
+ })
+ }
+}
+
+#[proc_macro]
+pub fn lazy_static(input: TokenStream) -> TokenStream {
+ let LazyStatic {
+ visibility,
+ name,
+ ty,
+ init,
+ } = parse_macro_input!(input as LazyStatic);
+
+ // The warning looks like this.
+ //
+ // warning: come on, pick a more creative name
+ // --> src/main.rs:10:16
+ // |
+ // 10 | static ref FOO: String = "lazy_static".to_owned();
+ // | ^^^
+ if name == "FOO" {
+ name.span()
+ .unwrap()
+ .warning("come on, pick a more creative name")
+ .emit();
+ }
+
+ // The error looks like this.
+ //
+ // error: I can't think of a legitimate use for lazily initializing the value `()`
+ // --> src/main.rs:10:27
+ // |
+ // 10 | static ref UNIT: () = ();
+ // | ^^
+ if let Expr::Tuple(ref init) = init {
+ if init.elems.is_empty() {
+ init.span()
+ .unwrap()
+ .error("I can't think of a legitimate use for lazily initializing the value `()`")
+ .emit();
+ return TokenStream::new();
+ }
+ }
+
+ // Assert that the static type implements Sync. If not, user sees an error
+ // message like the following. We span this assertion with the field type's
+ // line/column so that the error message appears in the correct place.
+ //
+ // error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
+ // --> src/main.rs:10:21
+ // |
+ // 10 | static ref PTR: *const () = &();
+ // | ^^^^^^^^^ `*const ()` cannot be shared between threads safely
+ let assert_sync = quote_spanned! {ty.span()=>
+ struct _AssertSync where #ty: std::marker::Sync;
+ };
+
+ // Check for Sized. Not vital to check here, but the error message is less
+ // confusing this way than if they get a Sized error in one of our
+ // implementation details where it assumes Sized.
+ //
+ // error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ // --> src/main.rs:10:19
+ // |
+ // 10 | static ref A: str = "";
+ // | ^^^ `str` does not have a constant size known at compile-time
+ let assert_sized = quote_spanned! {ty.span()=>
+ struct _AssertSized where #ty: std::marker::Sized;
+ };
+
+ let init_ptr = quote_spanned! {init.span()=>
+ Box::into_raw(Box::new(#init))
+ };
+
+ let expanded = quote! {
+ #visibility struct #name;
+
+ impl std::ops::Deref for #name {
+ type Target = #ty;
+
+ fn deref(&self) -> &#ty {
+ #assert_sync
+ #assert_sized
+
+ static ONCE: std::sync::Once = std::sync::Once::new();
+ static mut VALUE: *mut #ty = 0 as *mut #ty;
+
+ unsafe {
+ ONCE.call_once(|| VALUE = #init_ptr);
+ &*VALUE
+ }
+ }
+ }
+ };
+
+ TokenStream::from(expanded)
+}
diff --git a/syn/examples/trace-var/Cargo.toml b/syn/examples/trace-var/Cargo.toml
new file mode 100644
index 0000000..b54454d
--- /dev/null
+++ b/syn/examples/trace-var/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["example", "trace-var"]
diff --git a/syn/examples/trace-var/README.md b/syn/examples/trace-var/README.md
new file mode 100644
index 0000000..b93fae2
--- /dev/null
+++ b/syn/examples/trace-var/README.md
@@ -0,0 +1,61 @@
+An example of an attribute procedural macro. The `#[trace_var(...)]` attribute
+prints the value of the given variables each time they are reassigned.
+
+- [`trace-var/src/lib.rs`](trace-var/src/lib.rs)
+- [`example/src/main.rs`](example/src/main.rs)
+
+Consider the following factorial implementation.
+
+```rust
+#[trace_var(p, n)]
+fn factorial(mut n: u64) -> u64 {
+ let mut p = 1;
+ while n > 1 {
+ p *= n;
+ n -= 1;
+ }
+ p
+}
+```
+
+Invoking this with `factorial(8)` prints all the values of `p` and `n` during
+the execution of the function.
+
+```
+p = 1
+p = 8
+n = 7
+p = 56
+n = 6
+p = 336
+n = 5
+p = 1680
+n = 4
+p = 6720
+n = 3
+p = 20160
+n = 2
+p = 40320
+n = 1
+```
+
+The procedural macro uses a syntax tree [`Fold`] to rewrite every `let`
+statement and assignment expression in the following way:
+
+[`Fold`]: https://docs.rs/syn/1.0/syn/fold/trait.Fold.html
+
+```rust
+// Before
+let VAR = INIT;
+
+// After
+let VAR = { let VAR = INIT; println!("VAR = {:?}", VAR); VAR };
+```
+
+```rust
+// Before
+VAR = INIT
+
+// After
+{ VAR = INIT; println!("VAR = {:?}", VAR); }
+```
diff --git a/syn/examples/trace-var/example/Cargo.toml b/syn/examples/trace-var/example/Cargo.toml
new file mode 100644
index 0000000..d2ad650
--- /dev/null
+++ b/syn/examples/trace-var/example/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "example"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+trace-var = { path = "../trace-var" }
diff --git a/syn/examples/trace-var/example/src/main.rs b/syn/examples/trace-var/example/src/main.rs
new file mode 100644
index 0000000..da2c10b
--- /dev/null
+++ b/syn/examples/trace-var/example/src/main.rs
@@ -0,0 +1,15 @@
+use trace_var::trace_var;
+
+fn main() {
+ println!("{}", factorial(8));
+}
+
+#[trace_var(p, n)]
+fn factorial(mut n: u64) -> u64 {
+ let mut p = 1;
+ while n > 1 {
+ p *= n;
+ n -= 1;
+ }
+ p
+}
diff --git a/syn/examples/trace-var/trace-var/Cargo.toml b/syn/examples/trace-var/trace-var/Cargo.toml
new file mode 100644
index 0000000..72f56e9
--- /dev/null
+++ b/syn/examples/trace-var/trace-var/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "trace-var"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = { version = "1.0", features = ["nightly"] }
+quote = "1.0"
+syn = { path = "../../../", features = ["full", "fold"] }
diff --git a/syn/examples/trace-var/trace-var/src/lib.rs b/syn/examples/trace-var/trace-var/src/lib.rs
new file mode 100644
index 0000000..0ecfb47
--- /dev/null
+++ b/syn/examples/trace-var/trace-var/src/lib.rs
@@ -0,0 +1,180 @@
+extern crate proc_macro;
+use self::proc_macro::TokenStream;
+
+use quote::{quote, ToTokens};
+use std::collections::HashSet as Set;
+use syn::fold::{self, Fold};
+use syn::parse::{Parse, ParseStream, Result};
+use syn::punctuated::Punctuated;
+use syn::{parse_macro_input, parse_quote, Expr, Ident, ItemFn, Local, Pat, Stmt, Token};
+
+/// Parses a list of variable names separated by commas.
+///
+/// a, b, c
+///
+/// This is how the compiler passes in arguments to our attribute -- it is
+/// everything inside the delimiters after the attribute name.
+///
+/// #[trace_var(a, b, c)]
+/// ^^^^^^^
+struct Args {
+ vars: Set<Ident>,
+}
+
+impl Parse for Args {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let vars = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
+ Ok(Args {
+ vars: vars.into_iter().collect(),
+ })
+ }
+}
+
+impl Args {
+ /// Determines whether the given `Expr` is a path referring to one of the
+ /// variables we intend to print. Expressions are used as the left-hand side
+ /// of the assignment operator.
+ fn should_print_expr(&self, e: &Expr) -> bool {
+ match *e {
+ Expr::Path(ref e) => {
+ if e.path.leading_colon.is_some() {
+ false
+ } else if e.path.segments.len() != 1 {
+ false
+ } else {
+ let first = e.path.segments.first().unwrap();
+ self.vars.contains(&first.ident) && first.arguments.is_empty()
+ }
+ }
+ _ => false,
+ }
+ }
+
+ /// Determines whether the given `Pat` is an identifier equal to one of the
+ /// variables we intend to print. Patterns are used as the left-hand side of
+ /// a `let` binding.
+ fn should_print_pat(&self, p: &Pat) -> bool {
+ match p {
+ Pat::Ident(ref p) => self.vars.contains(&p.ident),
+ _ => false,
+ }
+ }
+
+ /// Produces an expression that assigns the right-hand side to the left-hand
+ /// side and then prints the value.
+ ///
+ /// // Before
+ /// VAR = INIT
+ ///
+ /// // After
+ /// { VAR = INIT; println!("VAR = {:?}", VAR); }
+ fn assign_and_print(&mut self, left: Expr, op: &dyn ToTokens, right: Expr) -> Expr {
+ let right = fold::fold_expr(self, right);
+ parse_quote!({
+ #left #op #right;
+ println!(concat!(stringify!(#left), " = {:?}"), #left);
+ })
+ }
+
+ /// Produces a let-binding that assigns the right-hand side to the left-hand
+ /// side and then prints the value.
+ ///
+ /// // Before
+ /// let VAR = INIT;
+ ///
+ /// // After
+ /// let VAR = { let VAR = INIT; println!("VAR = {:?}", VAR); VAR };
+ fn let_and_print(&mut self, local: Local) -> Stmt {
+ let Local { pat, init, .. } = local;
+ let init = self.fold_expr(*init.unwrap().1);
+ let ident = match pat {
+ Pat::Ident(ref p) => &p.ident,
+ _ => unreachable!(),
+ };
+ parse_quote! {
+ let #pat = {
+ #[allow(unused_mut)]
+ let #pat = #init;
+ println!(concat!(stringify!(#ident), " = {:?}"), #ident);
+ #ident
+ };
+ }
+ }
+}
+
+/// The `Fold` trait is a way to traverse an owned syntax tree and replace some
+/// of its nodes.
+///
+/// Syn provides two other syntax tree traversal traits: `Visit` which walks a
+/// shared borrow of a syntax tree, and `VisitMut` which walks an exclusive
+/// borrow of a syntax tree and can mutate it in place.
+///
+/// All three traits have a method corresponding to each type of node in Syn's
+/// syntax tree. All of these methods have default no-op implementations that
+/// simply recurse on any child nodes. We can override only those methods for
+/// which we want non-default behavior. In this case the traversal needs to
+/// transform `Expr` and `Stmt` nodes.
+impl Fold for Args {
+ fn fold_expr(&mut self, e: Expr) -> Expr {
+ match e {
+ Expr::Assign(e) => {
+ if self.should_print_expr(&e.left) {
+ self.assign_and_print(*e.left, &e.eq_token, *e.right)
+ } else {
+ Expr::Assign(fold::fold_expr_assign(self, e))
+ }
+ }
+ Expr::AssignOp(e) => {
+ if self.should_print_expr(&e.left) {
+ self.assign_and_print(*e.left, &e.op, *e.right)
+ } else {
+ Expr::AssignOp(fold::fold_expr_assign_op(self, e))
+ }
+ }
+ _ => fold::fold_expr(self, e),
+ }
+ }
+
+ fn fold_stmt(&mut self, s: Stmt) -> Stmt {
+ match s {
+ Stmt::Local(s) => {
+ if s.init.is_some() && self.should_print_pat(&s.pat) {
+ self.let_and_print(s)
+ } else {
+ Stmt::Local(fold::fold_local(self, s))
+ }
+ }
+ _ => fold::fold_stmt(self, s),
+ }
+ }
+}
+
+/// Attribute to print the value of the given variables each time they are
+/// reassigned.
+///
+/// # Example
+///
+/// ```
+/// #[trace_var(p, n)]
+/// fn factorial(mut n: u64) -> u64 {
+/// let mut p = 1;
+/// while n > 1 {
+/// p *= n;
+/// n -= 1;
+/// }
+/// p
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn trace_var(args: TokenStream, input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as ItemFn);
+
+ // Parse the list of variables the user wanted to print.
+ let mut args = parse_macro_input!(args as Args);
+
+ // Use a syntax tree traversal to transform the function body.
+ let output = args.fold_item_fn(input);
+
+ // Hand the resulting function body back to the compiler.
+ TokenStream::from(quote!(#output))
+}
diff --git a/syn/json/Cargo.toml b/syn/json/Cargo.toml
new file mode 100644
index 0000000..77104dc
--- /dev/null
+++ b/syn/json/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "syn-codegen"
+version = "0.1.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+edition = "2018"
+license = "MIT OR Apache-2.0"
+description = "Syntax tree describing Syn's syntax tree"
+repository = "https://github.com/dtolnay/syn"
+documentation = "https://docs.rs/syn-codegen"
+categories = ["development-tools::procedural-macro-helpers"]
+
+[dependencies]
+indexmap = { version = "1.0", features = ["serde-1"] }
+semver = { version = "0.9", features = ["serde"] }
+serde = { version = "1.0.88", features = ["derive"] }
+
+[dev-dependencies]
+serde_json = "1.0"
diff --git a/syn/json/src/lib.rs b/syn/json/src/lib.rs
new file mode 100644
index 0000000..e3546d9
--- /dev/null
+++ b/syn/json/src/lib.rs
@@ -0,0 +1,214 @@
+//! # Data structures that describe Syn's syntax tree.
+//!
+//! The Syn syntax tree is made up of more than 200 types. Occasionally it can
+//! come up that you need to implement some behavior across them all.
+//!
+//! - For example [the Rust integration for AST Explorer][astexplorer] wants to
+//! turn a syntax tree from Syn into a JavaScript value understood by the
+//! platform's existing cross-language syntax tree visualization code.
+//!
+//! [astexplorer]: https://astexplorer.net/#/gist/388150a52f74d45a355d2b5e865ded96/0c6d563f28d900472f699c21a1845ad20ae9927f
+//!
+//! - As another example from within Syn itself, the traits and implementations
+//! of the [`visit`], [`visit_mut`], and [`fold`] modules can be generated
+//! programmatically from a description of the syntax tree.
+//!
+//! [`visit`]: https://docs.rs/syn/1.0/syn/visit/index.html
+//! [`visit_mut`]: https://docs.rs/syn/1.0/syn/visit_mut/index.html
+//! [`fold`]: https://docs.rs/syn/1.0/syn/fold/index.html
+//!
+//! To make this type of code as easy as possible to implement in any language,
+//! every Syn release comes with a machine-readable description of that version
+//! of the syntax tree as a JSON file [syn.json]. This `syn-codegen` crate
+//! provides the canonical data structures for parsing and making use of the
+//! representation in syn.json from Rust code.
+//!
+//! [syn.json]: https://raw.githubusercontent.com/dtolnay/syn/master/syn.json
+//!
+//! ## Example
+//!
+//! ```
+//! use syn_codegen::Definitions;
+//!
+//! # const IGNORE: &str = stringify! {
+//! const SYN: &str = include_str!("syn.json");
+//! # };
+//! # const SYN: &str = include_str!("../../syn.json");
+//!
+//! fn main() {
+//! let defs: Definitions = serde_json::from_str(SYN).unwrap();
+//!
+//! for node in &defs.types {
+//! println!("syn::{}", node.ident);
+//! }
+//! }
+//! ```
+
+use indexmap::IndexMap;
+use semver::Version;
+use serde::{Deserialize, Deserializer, Serialize};
+
+use std::collections::{BTreeMap, BTreeSet};
+
+/// Top-level content of the syntax tree description.
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct Definitions {
+ /// The Syn version whose syntax tree is described by this data.
+ pub version: Version,
+
+ /// Syntax tree types defined by Syn.
+ pub types: Vec<Node>,
+
+ /// Token types defined by Syn (keywords as well as punctuation).
+ ///
+ /// The keys in the map are the Rust type name for the token. The values in
+ /// the map are the printed token representation.
+ ///
+ /// These tokens are accessible in the Syn public API as `syn::token::#name`
+ /// or alternatively `syn::Token![#repr]`.
+ pub tokens: BTreeMap<String, String>,
+}
+
+/// Syntax tree type defined by Syn.
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct Node {
+ /// Name of the type.
+ ///
+ /// This type is accessible in the Syn public API as `syn::#name`.
+ pub ident: String,
+
+ /// Features behind which this type is cfg gated.
+ pub features: Features,
+
+ /// Content of the data structure.
+ #[serde(
+ flatten,
+ skip_serializing_if = "is_private",
+ deserialize_with = "private_if_absent"
+ )]
+ pub data: Data,
+
+ #[serde(skip_serializing_if = "is_true", default = "bool_true")]
+ pub exhaustive: bool,
+}
+
+/// Content of a syntax tree data structure.
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub enum Data {
+ /// This is an opaque type with no publicy accessible structure.
+ Private,
+
+ /// This type is a braced struct with named fields.
+ #[serde(rename = "fields")]
+ Struct(Fields),
+
+ /// This type is an enum.
+ #[serde(rename = "variants")]
+ Enum(Variants),
+}
+
+/// Fields of a braced struct syntax tree node with named fields.
+///
+/// The keys in the map are the field names.
+pub type Fields = IndexMap<String, Type>;
+
+/// Variants of an enum syntax tree node.
+///
+/// The keys in the map are the variant names.
+///
+/// Variants are unit variants if they hold no data and tuple variants
+/// otherwise. The Syn syntax tree does not make use of braced variants.
+pub type Variants = IndexMap<String, Vec<Type>>;
+
+/// Type of a struct field or tuple variant field in the syntax tree.
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "lowercase")]
+pub enum Type {
+ /// Syntax tree type defined by Syn.
+ ///
+ /// This name will match the ident of some `Node`.
+ Syn(String),
+
+ /// Type defined by the Rust language or standard library.
+ ///
+ /// All such types used by Syn are accessible in the Rust prelude and can be
+ /// used without a qualifying path in most Rust code.
+ Std(String),
+
+ /// Type defined by proc-macro2.
+ ///
+ /// The type is accessible in the proc-macro2 public API as
+ /// `proc_macro2::#name`.
+ #[serde(rename = "proc_macro2")]
+ Ext(String),
+
+ /// Keyword or punctuation token type defined by Syn.
+ ///
+ /// This name will match one of the keys in the `tokens` map.
+ Token(String),
+
+ /// Grouping token defined by Syn.
+ ///
+ /// The type is accessible in the Syn public API as `syn::token::#name`.
+ Group(String),
+
+ /// Punctuated list.
+ ///
+ /// This refers to `syn::punctuated::Punctuated<T, P>` with the specified
+ /// element type and punctuation.
+ Punctuated(Punctuated),
+
+ /// `std::option::Option`
+ Option(Box<Type>),
+
+ /// `std::boxed::Box`
+ Box(Box<Type>),
+
+ /// `std::vec::Vec`
+ Vec(Box<Type>),
+
+ /// Rust tuple with two or more fields.
+ Tuple(Vec<Type>),
+}
+
+/// Type of a punctuated list.
+///
+/// This refers to `syn::punctuated::Punctuated<#element, #punct>`.
+///
+/// The punct string will match one of the keys in the `tokens` map.
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct Punctuated {
+ pub element: Box<Type>,
+ pub punct: String,
+}
+
+/// Features behind which a syntax tree type is cfg gated.
+#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
+pub struct Features {
+ /// Type is accessible if at least one of these features is enabled against
+ /// the Syn dependency.
+ pub any: BTreeSet<String>,
+}
+
+fn is_private(data: &Data) -> bool {
+ match data {
+ Data::Private => true,
+ Data::Struct(_) | Data::Enum(_) => false,
+ }
+}
+
+fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ let option = Option::deserialize(deserializer)?;
+ Ok(option.unwrap_or(Data::Private))
+}
+
+fn is_true(b: &bool) -> bool {
+ *b
+}
+
+fn bool_true() -> bool {
+ true
+}
diff --git a/syn/src/attr.rs b/syn/src/attr.rs
new file mode 100644
index 0000000..a8e16ea
--- /dev/null
+++ b/syn/src/attr.rs
@@ -0,0 +1,682 @@
+use super::*;
+use crate::punctuated::Punctuated;
+
+use std::iter;
+
+use proc_macro2::TokenStream;
+
+#[cfg(feature = "parsing")]
+use crate::parse::{Parse, ParseBuffer, ParseStream, Parser, Result};
+#[cfg(feature = "parsing")]
+use crate::punctuated::Pair;
+#[cfg(feature = "extra-traits")]
+use crate::tt::TokenStreamHelper;
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+
+ast_struct! {
+ /// An attribute like `#[repr(transparent)]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// <br>
+ ///
+ /// # Syntax
+ ///
+ /// Rust has six types of attributes.
+ ///
+ /// - Outer attributes like `#[repr(transparent)]`. These appear outside or
+ /// in front of the item they describe.
+ /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside
+ /// of the item they describe, usually a module.
+ /// - Outer doc comments like `/// # Example`.
+ /// - Inner doc comments like `//! Please file an issue`.
+ /// - Outer block comments `/** # Example */`.
+ /// - Inner block comments `/*! Please file an issue */`.
+ ///
+ /// The `style` field of type `AttrStyle` distinguishes whether an attribute
+ /// is outer or inner. Doc comments and block comments are promoted to
+ /// attributes, as this is how they are processed by the compiler and by
+ /// `macro_rules!` macros.
+ ///
+ /// The `path` field gives the possibly colon-delimited path against which
+ /// the attribute is resolved. It is equal to `"doc"` for desugared doc
+ /// comments. The `tokens` field contains the rest of the attribute body as
+ /// tokens.
+ ///
+ /// ```text
+ /// #[derive(Copy)] #[crate::precondition x < 5]
+ /// ^^^^^^~~~~~~ ^^^^^^^^^^^^^^^^^^^ ~~~~~
+ /// path tokens path tokens
+ /// ```
+ ///
+ /// <br>
+ ///
+ /// # Parsing from tokens to Attribute
+ ///
+ /// This type does not implement the [`Parse`] trait and thus cannot be
+ /// parsed directly by [`ParseStream::parse`]. Instead use
+ /// [`ParseStream::call`] with one of the two parser functions
+ /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on
+ /// which you intend to parse.
+ ///
+ /// [`Parse`]: parse::Parse
+ /// [`ParseStream::parse`]: parse::ParseBuffer::parse
+ /// [`ParseStream::call`]: parse::ParseBuffer::call
+ ///
+ /// ```
+ /// use syn::{Attribute, Ident, Result, Token};
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// // Parses a unit struct with attributes.
+ /// //
+ /// // #[path = "s.tmpl"]
+ /// // struct S;
+ /// struct UnitStruct {
+ /// attrs: Vec<Attribute>,
+ /// struct_token: Token![struct],
+ /// name: Ident,
+ /// semi_token: Token![;],
+ /// }
+ ///
+ /// impl Parse for UnitStruct {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// Ok(UnitStruct {
+ /// attrs: input.call(Attribute::parse_outer)?,
+ /// struct_token: input.parse()?,
+ /// name: input.parse()?,
+ /// semi_token: input.parse()?,
+ /// })
+ /// }
+ /// }
+ /// ```
+ ///
+ /// <p><br></p>
+ ///
+ /// # Parsing from Attribute to structured arguments
+ ///
+ /// The grammar of attributes in Rust is very flexible, which makes the
+ /// syntax tree not that useful on its own. In particular, arguments of the
+ /// attribute are held in an arbitrary `tokens: TokenStream`. Macros are
+ /// expected to check the `path` of the attribute, decide whether they
+ /// recognize it, and then parse the remaining tokens according to whatever
+ /// grammar they wish to require for that kind of attribute.
+ ///
+ /// If the attribute you are parsing is expected to conform to the
+ /// conventional structured form of attribute, use [`parse_meta()`] to
+ /// obtain that structured representation. If the attribute follows some
+ /// other grammar of its own, use [`parse_args()`] to parse that into the
+ /// expected data structure.
+ ///
+ /// [`parse_meta()`]: Attribute::parse_meta
+ /// [`parse_args()`]: Attribute::parse_args
+ ///
+ /// <p><br></p>
+ ///
+ /// # Doc comments
+ ///
+ /// The compiler transforms doc comments, such as `/// comment` and `/*!
+ /// comment */`, into attributes before macros are expanded. Each comment is
+ /// expanded into an attribute of the form `#[doc = r"comment"]`.
+ ///
+ /// As an example, the following `mod` items are expanded identically:
+ ///
+ /// ```
+ /// # use syn::{ItemMod, parse_quote};
+ /// let doc: ItemMod = parse_quote! {
+ /// /// Single line doc comments
+ /// /// We write so many!
+ /// /**
+ /// * Multi-line comments...
+ /// * May span many lines
+ /// */
+ /// mod example {
+ /// //! Of course, they can be inner too
+ /// /*! And fit in a single line */
+ /// }
+ /// };
+ /// let attr: ItemMod = parse_quote! {
+ /// #[doc = r" Single line doc comments"]
+ /// #[doc = r" We write so many!"]
+ /// #[doc = r" Multi-line comments...
+ /// May span many lines"]
+ /// mod example {
+ /// #![doc = r" Of course, they can be inner too"]
+ /// #![doc = r" And fit in a single line "]
+ /// }
+ /// };
+ /// assert_eq!(doc, attr);
+ /// ```
+ pub struct Attribute #manual_extra_traits {
+ pub pound_token: Token![#],
+ pub style: AttrStyle,
+ pub bracket_token: token::Bracket,
+ pub path: Path,
+ pub tokens: TokenStream,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Attribute {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Attribute {
+ fn eq(&self, other: &Self) -> bool {
+ self.style == other.style
+ && self.pound_token == other.pound_token
+ && self.bracket_token == other.bracket_token
+ && self.path == other.path
+ && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Attribute {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.style.hash(state);
+ self.pound_token.hash(state);
+ self.bracket_token.hash(state);
+ self.path.hash(state);
+ TokenStreamHelper(&self.tokens).hash(state);
+ }
+}
+
+impl Attribute {
+ /// Parses the content of the attribute, consisting of the path and tokens,
+ /// as a [`Meta`] if possible.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_meta(&self) -> Result<Meta> {
+ fn clone_ident_segment(segment: &PathSegment) -> PathSegment {
+ PathSegment {
+ ident: segment.ident.clone(),
+ arguments: PathArguments::None,
+ }
+ }
+
+ let path = Path {
+ leading_colon: self
+ .path
+ .leading_colon
+ .as_ref()
+ .map(|colon| Token![::](colon.spans)),
+ segments: self
+ .path
+ .segments
+ .pairs()
+ .map(|pair| match pair {
+ Pair::Punctuated(seg, punct) => {
+ Pair::Punctuated(clone_ident_segment(seg), Token![::](punct.spans))
+ }
+ Pair::End(seg) => Pair::End(clone_ident_segment(seg)),
+ })
+ .collect(),
+ };
+
+ let parser = |input: ParseStream| parsing::parse_meta_after_path(path, input);
+ parse::Parser::parse2(parser, self.tokens.clone())
+ }
+
+ /// Parse the arguments to the attribute as a syntax tree.
+ ///
+ /// This is similar to `syn::parse2::<T>(attr.tokens)` except that:
+ ///
+ /// - the surrounding delimiters are *not* included in the input to the
+ /// parser; and
+ /// - the error message has a more useful span when `tokens` is empty.
+ ///
+ /// ```text
+ /// #[my_attr(value < 5)]
+ /// ^^^^^^^^^ what gets parsed
+ /// ```
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_args<T: Parse>(&self) -> Result<T> {
+ self.parse_args_with(T::parse)
+ }
+
+ /// Parse the arguments to the attribute using the given parser.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
+ let parser = |input: ParseStream| {
+ let args = enter_args(self, input)?;
+ parse::parse_stream(parser, &args)
+ };
+ parser.parse2(self.tokens.clone())
+ }
+
+ /// Parses zero or more outer attributes from the stream.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
+ let mut attrs = Vec::new();
+ while input.peek(Token![#]) {
+ attrs.push(input.call(parsing::single_parse_outer)?);
+ }
+ Ok(attrs)
+ }
+
+ /// Parses zero or more inner attributes from the stream.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {
+ let mut attrs = Vec::new();
+ while input.peek(Token![#]) && input.peek2(Token![!]) {
+ attrs.push(input.call(parsing::single_parse_inner)?);
+ }
+ Ok(attrs)
+ }
+}
+
+#[cfg(feature = "parsing")]
+fn error_expected_args(attr: &Attribute) -> Error {
+ let style = match attr.style {
+ AttrStyle::Outer => "#",
+ AttrStyle::Inner(_) => "#!",
+ };
+
+ let mut path = String::new();
+ for segment in &attr.path.segments {
+ if !path.is_empty() || attr.path.leading_colon.is_some() {
+ path += "::";
+ }
+ path += &segment.ident.to_string();
+ }
+
+ let msg = format!("expected attribute arguments: {}[{}(...)]", style, path);
+
+ #[cfg(feature = "printing")]
+ return Error::new_spanned(attr, msg);
+
+ #[cfg(not(feature = "printing"))]
+ return Error::new(attr.bracket_token.span, msg);
+}
+
+#[cfg(feature = "parsing")]
+fn enter_args<'a>(attr: &Attribute, input: ParseStream<'a>) -> Result<ParseBuffer<'a>> {
+ if input.is_empty() {
+ return Err(error_expected_args(attr));
+ };
+
+ let content;
+ if input.peek(token::Paren) {
+ parenthesized!(content in input);
+ } else if input.peek(token::Bracket) {
+ bracketed!(content in input);
+ } else if input.peek(token::Brace) {
+ braced!(content in input);
+ } else {
+ return Err(input.error("unexpected token in attribute arguments"));
+ }
+
+ if input.is_empty() {
+ Ok(content)
+ } else {
+ Err(input.error("unexpected token in attribute arguments"))
+ }
+}
+
+ast_enum! {
+ /// Distinguishes between attributes that decorate an item and attributes
+ /// that are contained within an item.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Outer attributes
+ ///
+ /// - `#[repr(transparent)]`
+ /// - `/// # Example`
+ /// - `/** Please file an issue */`
+ ///
+ /// # Inner attributes
+ ///
+ /// - `#![feature(proc_macro)]`
+ /// - `//! # Example`
+ /// - `/*! Please file an issue */`
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum AttrStyle {
+ Outer,
+ Inner(Token![!]),
+ }
+}
+
+ast_enum_of_structs! {
+ /// Content of a compile-time structured attribute.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// ## Path
+ ///
+ /// A meta path is like the `test` in `#[test]`.
+ ///
+ /// ## List
+ ///
+ /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`.
+ ///
+ /// ## NameValue
+ ///
+ /// A name-value meta is like the `path = "..."` in `#[path =
+ /// "sys/windows.rs"]`.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum Meta {
+ Path(Path),
+
+ /// A structured list within an attribute, like `derive(Copy, Clone)`.
+ List(MetaList),
+
+ /// A name-value pair within an attribute, like `feature = "nightly"`.
+ NameValue(MetaNameValue),
+ }
+}
+
+ast_struct! {
+ /// A structured list within an attribute, like `derive(Copy, Clone)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct MetaList {
+ pub path: Path,
+ pub paren_token: token::Paren,
+ pub nested: Punctuated<NestedMeta, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A name-value pair within an attribute, like `feature = "nightly"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct MetaNameValue {
+ pub path: Path,
+ pub eq_token: Token![=],
+ pub lit: Lit,
+ }
+}
+
+impl Meta {
+ /// Returns the identifier that begins this structured meta item.
+ ///
+ /// For example this would return the `test` in `#[test]`, the `derive` in
+ /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.
+ pub fn path(&self) -> &Path {
+ match self {
+ Meta::Path(path) => path,
+ Meta::List(meta) => &meta.path,
+ Meta::NameValue(meta) => &meta.path,
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// Element of a compile-time attribute list.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum NestedMeta {
+ /// A structured meta item, like the `Copy` in `#[derive(Copy)]` which
+ /// would be a nested `Meta::Path`.
+ Meta(Meta),
+
+ /// A Rust literal, like the `"new_name"` in `#[rename("new_name")]`.
+ Lit(Lit),
+ }
+}
+
+/// Conventional argument type associated with an invocation of an attribute
+/// macro.
+///
+/// For example if we are developing an attribute macro that is intended to be
+/// invoked on function items as follows:
+///
+/// ```
+/// # const IGNORE: &str = stringify! {
+/// #[my_attribute(path = "/v1/refresh")]
+/// # };
+/// pub fn refresh() {
+/// /* ... */
+/// }
+/// ```
+///
+/// The implementation of this macro would want to parse its attribute arguments
+/// as type `AttributeArgs`.
+///
+/// ```
+/// extern crate proc_macro;
+///
+/// use proc_macro::TokenStream;
+/// use syn::{parse_macro_input, AttributeArgs, ItemFn};
+///
+/// # const IGNORE: &str = stringify! {
+/// #[proc_macro_attribute]
+/// # };
+/// pub fn my_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
+/// let args = parse_macro_input!(args as AttributeArgs);
+/// let input = parse_macro_input!(input as ItemFn);
+///
+/// /* ... */
+/// # "".parse().unwrap()
+/// }
+/// ```
+pub type AttributeArgs = Vec<NestedMeta>;
+
+pub trait FilterAttrs<'a> {
+ type Ret: Iterator<Item = &'a Attribute>;
+
+ fn outer(self) -> Self::Ret;
+ fn inner(self) -> Self::Ret;
+}
+
+impl<'a, T> FilterAttrs<'a> for T
+where
+ T: IntoIterator<Item = &'a Attribute>,
+{
+ type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;
+
+ fn outer(self) -> Self::Ret {
+ fn is_outer(attr: &&Attribute) -> bool {
+ match attr.style {
+ AttrStyle::Outer => true,
+ _ => false,
+ }
+ }
+ self.into_iter().filter(is_outer)
+ }
+
+ fn inner(self) -> Self::Ret {
+ fn is_inner(attr: &&Attribute) -> bool {
+ match attr.style {
+ AttrStyle::Inner(_) => true,
+ _ => false,
+ }
+ }
+ self.into_iter().filter(is_inner)
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::ext::IdentExt;
+ use crate::parse::{Parse, ParseStream, Result};
+ #[cfg(feature = "full")]
+ use crate::private;
+
+ pub fn single_parse_inner(input: ParseStream) -> Result<Attribute> {
+ let content;
+ Ok(Attribute {
+ pound_token: input.parse()?,
+ style: AttrStyle::Inner(input.parse()?),
+ bracket_token: bracketed!(content in input),
+ path: content.call(Path::parse_mod_style)?,
+ tokens: content.parse()?,
+ })
+ }
+
+ pub fn single_parse_outer(input: ParseStream) -> Result<Attribute> {
+ let content;
+ Ok(Attribute {
+ pound_token: input.parse()?,
+ style: AttrStyle::Outer,
+ bracket_token: bracketed!(content in input),
+ path: content.call(Path::parse_mod_style)?,
+ tokens: content.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ impl private {
+ pub fn attrs(outer: Vec<Attribute>, inner: Vec<Attribute>) -> Vec<Attribute> {
+ let mut attrs = outer;
+ attrs.extend(inner);
+ attrs
+ }
+ }
+
+ // Like Path::parse_mod_style but accepts keywords in the path.
+ fn parse_meta_path(input: ParseStream) -> Result<Path> {
+ Ok(Path {
+ leading_colon: input.parse()?,
+ segments: {
+ let mut segments = Punctuated::new();
+ while input.peek(Ident::peek_any) {
+ let ident = Ident::parse_any(input)?;
+ segments.push_value(PathSegment::from(ident));
+ if !input.peek(Token![::]) {
+ break;
+ }
+ let punct = input.parse()?;
+ segments.push_punct(punct);
+ }
+ if segments.is_empty() {
+ return Err(input.error("expected path"));
+ } else if segments.trailing_punct() {
+ return Err(input.error("expected path segment"));
+ }
+ segments
+ },
+ })
+ }
+
+ impl Parse for Meta {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let path = input.call(parse_meta_path)?;
+ parse_meta_after_path(path, input)
+ }
+ }
+
+ impl Parse for MetaList {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let path = input.call(parse_meta_path)?;
+ parse_meta_list_after_path(path, input)
+ }
+ }
+
+ impl Parse for MetaNameValue {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let path = input.call(parse_meta_path)?;
+ parse_meta_name_value_after_path(path, input)
+ }
+ }
+
+ impl Parse for NestedMeta {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Lit) && !(input.peek(LitBool) && input.peek2(Token![=])) {
+ input.parse().map(NestedMeta::Lit)
+ } else if input.peek(Ident::peek_any) {
+ input.parse().map(NestedMeta::Meta)
+ } else {
+ Err(input.error("expected identifier or literal"))
+ }
+ }
+ }
+
+ pub fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> {
+ if input.peek(token::Paren) {
+ parse_meta_list_after_path(path, input).map(Meta::List)
+ } else if input.peek(Token![=]) {
+ parse_meta_name_value_after_path(path, input).map(Meta::NameValue)
+ } else {
+ Ok(Meta::Path(path))
+ }
+ }
+
+ fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> {
+ let content;
+ Ok(MetaList {
+ path,
+ paren_token: parenthesized!(content in input),
+ nested: content.parse_terminated(NestedMeta::parse)?,
+ })
+ }
+
+ fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> {
+ Ok(MetaNameValue {
+ path,
+ eq_token: input.parse()?,
+ lit: input.parse()?,
+ })
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for Attribute {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.pound_token.to_tokens(tokens);
+ if let AttrStyle::Inner(b) = &self.style {
+ b.to_tokens(tokens);
+ }
+ self.bracket_token.surround(tokens, |tokens| {
+ self.path.to_tokens(tokens);
+ self.tokens.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for MetaList {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.nested.to_tokens(tokens);
+ })
+ }
+ }
+
+ impl ToTokens for MetaNameValue {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.lit.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn/src/await.rs b/syn/src/await.rs
new file mode 100644
index 0000000..a8e24fd
--- /dev/null
+++ b/syn/src/await.rs
@@ -0,0 +1,2 @@
+// See include!("await.rs") in token.rs.
+export_token_macro![(await)];
diff --git a/syn/src/bigint.rs b/syn/src/bigint.rs
new file mode 100644
index 0000000..5397d6b
--- /dev/null
+++ b/syn/src/bigint.rs
@@ -0,0 +1,66 @@
+use std::ops::{AddAssign, MulAssign};
+
+// For implementing base10_digits() accessor on LitInt.
+pub struct BigInt {
+ digits: Vec<u8>,
+}
+
+impl BigInt {
+ pub fn new() -> Self {
+ BigInt { digits: Vec::new() }
+ }
+
+ pub fn to_string(&self) -> String {
+ let mut repr = String::with_capacity(self.digits.len());
+
+ let mut has_nonzero = false;
+ for digit in self.digits.iter().rev() {
+ has_nonzero |= *digit != 0;
+ if has_nonzero {
+ repr.push((*digit + b'0') as char);
+ }
+ }
+
+ if repr.is_empty() {
+ repr.push('0');
+ }
+
+ repr
+ }
+
+ fn reserve_two_digits(&mut self) {
+ let len = self.digits.len();
+ let desired =
+ len + !self.digits.ends_with(&[0, 0]) as usize + !self.digits.ends_with(&[0]) as usize;
+ self.digits.resize(desired, 0);
+ }
+}
+
+impl AddAssign<u8> for BigInt {
+ // Assumes increment <16.
+ fn add_assign(&mut self, mut increment: u8) {
+ self.reserve_two_digits();
+
+ let mut i = 0;
+ while increment > 0 {
+ let sum = self.digits[i] + increment;
+ self.digits[i] = sum % 10;
+ increment = sum / 10;
+ i += 1;
+ }
+ }
+}
+
+impl MulAssign<u8> for BigInt {
+ // Assumes base <=16.
+ fn mul_assign(&mut self, base: u8) {
+ self.reserve_two_digits();
+
+ let mut carry = 0;
+ for digit in &mut self.digits {
+ let prod = *digit * base + carry;
+ *digit = prod % 10;
+ carry = prod / 10;
+ }
+ }
+}
diff --git a/syn/src/buffer.rs b/syn/src/buffer.rs
new file mode 100644
index 0000000..5c2dd8a
--- /dev/null
+++ b/syn/src/buffer.rs
@@ -0,0 +1,382 @@
+//! A stably addressed token buffer supporting efficient traversal based on a
+//! cheaply copyable cursor.
+//!
+//! *This module is available if Syn is built with the `"parsing"` feature.*
+
+// This module is heavily commented as it contains most of the unsafe code in
+// Syn, and caution should be used when editing it. The public-facing interface
+// is 100% safe but the implementation is fragile internally.
+
+#[cfg(all(
+ not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
+ feature = "proc-macro"
+))]
+use crate::proc_macro as pm;
+use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
+
+use std::marker::PhantomData;
+use std::ptr;
+
+use crate::Lifetime;
+
+/// Internal type which is used instead of `TokenTree` to represent a token tree
+/// within a `TokenBuffer`.
+enum Entry {
+ // Mimicking types from proc-macro.
+ Group(Group, TokenBuffer),
+ Ident(Ident),
+ Punct(Punct),
+ Literal(Literal),
+ // End entries contain a raw pointer to the entry from the containing
+ // token tree, or null if this is the outermost level.
+ End(*const Entry),
+}
+
+/// A buffer that can be efficiently traversed multiple times, unlike
+/// `TokenStream` which requires a deep copy in order to traverse more than
+/// once.
+///
+/// *This type is available if Syn is built with the `"parsing"` feature.*
+pub struct TokenBuffer {
+ // NOTE: Do not derive clone on this - there are raw pointers inside which
+ // will be messed up. Moving the `TokenBuffer` itself is safe as the actual
+ // backing slices won't be moved.
+ data: Box<[Entry]>,
+}
+
+impl TokenBuffer {
+ // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT
+ // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE.
+ fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer {
+ // Build up the entries list, recording the locations of any Groups
+ // in the list to be processed later.
+ let mut entries = Vec::new();
+ let mut seqs = Vec::new();
+ for tt in stream {
+ match tt {
+ TokenTree::Ident(sym) => {
+ entries.push(Entry::Ident(sym));
+ }
+ TokenTree::Punct(op) => {
+ entries.push(Entry::Punct(op));
+ }
+ TokenTree::Literal(l) => {
+ entries.push(Entry::Literal(l));
+ }
+ TokenTree::Group(g) => {
+ // Record the index of the interesting entry, and store an
+ // `End(null)` there temporarially.
+ seqs.push((entries.len(), g));
+ entries.push(Entry::End(ptr::null()));
+ }
+ }
+ }
+ // Add an `End` entry to the end with a reference to the enclosing token
+ // stream which was passed in.
+ entries.push(Entry::End(up));
+
+ // NOTE: This is done to ensure that we don't accidentally modify the
+ // length of the backing buffer. The backing buffer must remain at a
+ // constant address after this point, as we are going to store a raw
+ // pointer into it.
+ let mut entries = entries.into_boxed_slice();
+ for (idx, group) in seqs {
+ // We know that this index refers to one of the temporary
+ // `End(null)` entries, and we know that the last entry is
+ // `End(up)`, so the next index is also valid.
+ let seq_up = &entries[idx + 1] as *const Entry;
+
+ // The end entry stored at the end of this Entry::Group should
+ // point to the Entry which follows the Group in the list.
+ let inner = Self::inner_new(group.stream(), seq_up);
+ entries[idx] = Entry::Group(group, inner);
+ }
+
+ TokenBuffer { data: entries }
+ }
+
+ /// Creates a `TokenBuffer` containing all the tokens from the input
+ /// `TokenStream`.
+ ///
+ /// *This method is available if Syn is built with both the `"parsing"` and
+ /// `"proc-macro"` features.*
+ #[cfg(all(
+ not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
+ feature = "proc-macro"
+ ))]
+ pub fn new(stream: pm::TokenStream) -> TokenBuffer {
+ Self::new2(stream.into())
+ }
+
+ /// Creates a `TokenBuffer` containing all the tokens from the input
+ /// `TokenStream`.
+ pub fn new2(stream: TokenStream) -> TokenBuffer {
+ Self::inner_new(stream, ptr::null())
+ }
+
+ /// Creates a cursor referencing the first token in the buffer and able to
+ /// traverse until the end of the buffer.
+ pub fn begin(&self) -> Cursor {
+ unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) }
+ }
+}
+
+/// A cheaply copyable cursor into a `TokenBuffer`.
+///
+/// This cursor holds a shared reference into the immutable data which is used
+/// internally to represent a `TokenStream`, and can be efficiently manipulated
+/// and copied around.
+///
+/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer`
+/// object and get a cursor to its first token with `begin()`.
+///
+/// Two cursors are equal if they have the same location in the same input
+/// stream, and have the same scope.
+///
+/// *This type is available if Syn is built with the `"parsing"` feature.*
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct Cursor<'a> {
+ // The current entry which the `Cursor` is pointing at.
+ ptr: *const Entry,
+ // This is the only `Entry::End(..)` object which this cursor is allowed to
+ // point at. All other `End` objects are skipped over in `Cursor::create`.
+ scope: *const Entry,
+ // Cursor is covariant in 'a. This field ensures that our pointers are still
+ // valid.
+ marker: PhantomData<&'a Entry>,
+}
+
+impl<'a> Cursor<'a> {
+ /// Creates a cursor referencing a static empty TokenStream.
+ pub fn empty() -> Self {
+ // It's safe in this situation for us to put an `Entry` object in global
+ // storage, despite it not actually being safe to send across threads
+ // (`Ident` is a reference into a thread-local table). This is because
+ // this entry never includes a `Ident` object.
+ //
+ // This wrapper struct allows us to break the rules and put a `Sync`
+ // object in global storage.
+ struct UnsafeSyncEntry(Entry);
+ unsafe impl Sync for UnsafeSyncEntry {}
+ static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry));
+
+ Cursor {
+ ptr: &EMPTY_ENTRY.0,
+ scope: &EMPTY_ENTRY.0,
+ marker: PhantomData,
+ }
+ }
+
+ /// This create method intelligently exits non-explicitly-entered
+ /// `None`-delimited scopes when the cursor reaches the end of them,
+ /// allowing for them to be treated transparently.
+ unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
+ // NOTE: If we're looking at a `End(..)`, we want to advance the cursor
+ // past it, unless `ptr == scope`, which means that we're at the edge of
+ // our cursor's scope. We should only have `ptr != scope` at the exit
+ // from None-delimited groups entered with `ignore_none`.
+ while let Entry::End(exit) = *ptr {
+ if ptr == scope {
+ break;
+ }
+ ptr = exit;
+ }
+
+ Cursor {
+ ptr,
+ scope,
+ marker: PhantomData,
+ }
+ }
+
+ /// Get the current entry.
+ fn entry(self) -> &'a Entry {
+ unsafe { &*self.ptr }
+ }
+
+ /// Bump the cursor to point at the next token after the current one. This
+ /// is undefined behavior if the cursor is currently looking at an
+ /// `Entry::End`.
+ unsafe fn bump(self) -> Cursor<'a> {
+ Cursor::create(self.ptr.offset(1), self.scope)
+ }
+
+ /// If the cursor is looking at a `None`-delimited group, move it to look at
+ /// the first token inside instead. If the group is empty, this will move
+ /// the cursor past the `None`-delimited group.
+ ///
+ /// WARNING: This mutates its argument.
+ fn ignore_none(&mut self) {
+ if let Entry::Group(group, buf) = self.entry() {
+ if group.delimiter() == Delimiter::None {
+ // NOTE: We call `Cursor::create` here to make sure that
+ // situations where we should immediately exit the span after
+ // entering it are handled correctly.
+ unsafe {
+ *self = Cursor::create(&buf.data[0], self.scope);
+ }
+ }
+ }
+ }
+
+ /// Checks whether the cursor is currently pointing at the end of its valid
+ /// scope.
+ pub fn eof(self) -> bool {
+ // We're at eof if we're at the end of our scope.
+ self.ptr == self.scope
+ }
+
+ /// If the cursor is pointing at a `Group` with the given delimiter, returns
+ /// a cursor into that group and one pointing to the next `TokenTree`.
+ pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
+ // If we're not trying to enter a none-delimited group, we want to
+ // ignore them. We have to make sure to _not_ ignore them when we want
+ // to enter them, of course. For obvious reasons.
+ if delim != Delimiter::None {
+ self.ignore_none();
+ }
+
+ if let Entry::Group(group, buf) = self.entry() {
+ if group.delimiter() == delim {
+ return Some((buf.begin(), group.span(), unsafe { self.bump() }));
+ }
+ }
+
+ None
+ }
+
+ /// If the cursor is pointing at a `Ident`, returns it along with a cursor
+ /// pointing at the next `TokenTree`.
+ pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
+ self.ignore_none();
+ match self.entry() {
+ Entry::Ident(ident) => Some((ident.clone(), unsafe { self.bump() })),
+ _ => None,
+ }
+ }
+
+ /// If the cursor is pointing at an `Punct`, returns it along with a cursor
+ /// pointing at the next `TokenTree`.
+ pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
+ self.ignore_none();
+ match self.entry() {
+ Entry::Punct(op) if op.as_char() != '\'' => Some((op.clone(), unsafe { self.bump() })),
+ _ => None,
+ }
+ }
+
+ /// If the cursor is pointing at a `Literal`, return it along with a cursor
+ /// pointing at the next `TokenTree`.
+ pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
+ self.ignore_none();
+ match self.entry() {
+ Entry::Literal(lit) => Some((lit.clone(), unsafe { self.bump() })),
+ _ => None,
+ }
+ }
+
+ /// If the cursor is pointing at a `Lifetime`, returns it along with a
+ /// cursor pointing at the next `TokenTree`.
+ pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
+ self.ignore_none();
+ match self.entry() {
+ Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
+ let next = unsafe { self.bump() };
+ match next.ident() {
+ Some((ident, rest)) => {
+ let lifetime = Lifetime {
+ apostrophe: op.span(),
+ ident,
+ };
+ Some((lifetime, rest))
+ }
+ None => None,
+ }
+ }
+ _ => None,
+ }
+ }
+
+ /// Copies all remaining tokens visible from this cursor into a
+ /// `TokenStream`.
+ pub fn token_stream(self) -> TokenStream {
+ let mut tts = Vec::new();
+ let mut cursor = self;
+ while let Some((tt, rest)) = cursor.token_tree() {
+ tts.push(tt);
+ cursor = rest;
+ }
+ tts.into_iter().collect()
+ }
+
+ /// If the cursor is pointing at a `TokenTree`, returns it along with a
+ /// cursor pointing at the next `TokenTree`.
+ ///
+ /// Returns `None` if the cursor has reached the end of its stream.
+ ///
+ /// This method does not treat `None`-delimited groups as transparent, and
+ /// will return a `Group(None, ..)` if the cursor is looking at one.
+ pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
+ let tree = match self.entry() {
+ Entry::Group(group, _) => group.clone().into(),
+ Entry::Literal(lit) => lit.clone().into(),
+ Entry::Ident(ident) => ident.clone().into(),
+ Entry::Punct(op) => op.clone().into(),
+ Entry::End(..) => {
+ return None;
+ }
+ };
+
+ Some((tree, unsafe { self.bump() }))
+ }
+
+ /// Returns the `Span` of the current token, or `Span::call_site()` if this
+ /// cursor points to eof.
+ pub fn span(self) -> Span {
+ match self.entry() {
+ Entry::Group(group, _) => group.span(),
+ Entry::Literal(l) => l.span(),
+ Entry::Ident(t) => t.span(),
+ Entry::Punct(o) => o.span(),
+ Entry::End(..) => Span::call_site(),
+ }
+ }
+
+ /// Skip over the next token without cloning it. Returns `None` if this
+ /// cursor points to eof.
+ ///
+ /// This method treats `'lifetimes` as a single token.
+ pub(crate) fn skip(self) -> Option<Cursor<'a>> {
+ match self.entry() {
+ Entry::End(..) => None,
+
+ // Treat lifetimes as a single tt for the purposes of 'skip'.
+ Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => {
+ let next = unsafe { self.bump() };
+ match next.entry() {
+ Entry::Ident(_) => Some(unsafe { next.bump() }),
+ _ => Some(next),
+ }
+ }
+ _ => Some(unsafe { self.bump() }),
+ }
+ }
+}
+
+pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool {
+ a.scope == b.scope
+}
+
+pub(crate) fn open_span_of_group(cursor: Cursor) -> Span {
+ match cursor.entry() {
+ Entry::Group(group, _) => group.span_open(),
+ _ => cursor.span(),
+ }
+}
+
+pub(crate) fn close_span_of_group(cursor: Cursor) -> Span {
+ match cursor.entry() {
+ Entry::Group(group, _) => group.span_close(),
+ _ => cursor.span(),
+ }
+}
diff --git a/syn/src/custom_keyword.rs b/syn/src/custom_keyword.rs
new file mode 100644
index 0000000..200e847
--- /dev/null
+++ b/syn/src/custom_keyword.rs
@@ -0,0 +1,252 @@
+/// Define a type that supports parsing and printing a given identifier as if it
+/// were a keyword.
+///
+/// # Usage
+///
+/// As a convention, it is recommended that this macro be invoked within a
+/// module called `kw` or `keyword` and that the resulting parser be invoked
+/// with a `kw::` or `keyword::` prefix.
+///
+/// ```
+/// mod kw {
+/// syn::custom_keyword!(whatever);
+/// }
+/// ```
+///
+/// The generated syntax tree node supports the following operations just like
+/// any built-in keyword token.
+///
+/// - [Peeking] — `input.peek(kw::whatever)`
+///
+/// - [Parsing] — `input.parse::<kw::whatever>()?`
+///
+/// - [Printing] — `quote!( ... #whatever_token ... )`
+///
+/// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)`
+///
+/// - Field access to its span — `let sp = whatever_token.span`
+///
+/// [Peeking]: parse::ParseBuffer::peek
+/// [Parsing]: parse::ParseBuffer::parse
+/// [Printing]: quote::ToTokens
+/// [`Span`]: proc_macro2::Span
+///
+/// # Example
+///
+/// This example parses input that looks like `bool = true` or `str = "value"`.
+/// The key must be either the identifier `bool` or the identifier `str`. If
+/// `bool`, the value may be either `true` or `false`. If `str`, the value may
+/// be any string literal.
+///
+/// The symbols `bool` and `str` are not reserved keywords in Rust so these are
+/// not considered keywords in the `syn::token` module. Like any other
+/// identifier that is not a keyword, these can be declared as custom keywords
+/// by crates that need to use them as such.
+///
+/// ```
+/// use syn::{LitBool, LitStr, Result, Token};
+/// use syn::parse::{Parse, ParseStream};
+///
+/// mod kw {
+/// syn::custom_keyword!(bool);
+/// syn::custom_keyword!(str);
+/// }
+///
+/// enum Argument {
+/// Bool {
+/// bool_token: kw::bool,
+/// eq_token: Token![=],
+/// value: LitBool,
+/// },
+/// Str {
+/// str_token: kw::str,
+/// eq_token: Token![=],
+/// value: LitStr,
+/// },
+/// }
+///
+/// impl Parse for Argument {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// let lookahead = input.lookahead1();
+/// if lookahead.peek(kw::bool) {
+/// Ok(Argument::Bool {
+/// bool_token: input.parse::<kw::bool>()?,
+/// eq_token: input.parse()?,
+/// value: input.parse()?,
+/// })
+/// } else if lookahead.peek(kw::str) {
+/// Ok(Argument::Str {
+/// str_token: input.parse::<kw::str>()?,
+/// eq_token: input.parse()?,
+/// value: input.parse()?,
+/// })
+/// } else {
+/// Err(lookahead.error())
+/// }
+/// }
+/// }
+/// ```
+#[macro_export(local_inner_macros)]
+macro_rules! custom_keyword {
+ ($ident:ident) => {
+ #[allow(non_camel_case_types)]
+ pub struct $ident {
+ pub span: $crate::export::Span,
+ }
+
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; 1]>>(
+ span: __S,
+ ) -> $ident {
+ $ident {
+ span: $crate::export::IntoSpans::into_spans(span)[0],
+ }
+ }
+
+ impl $crate::export::Default for $ident {
+ fn default() -> Self {
+ $ident {
+ span: $crate::export::Span::call_site(),
+ }
+ }
+ }
+
+ impl_parse_for_custom_keyword!($ident);
+ impl_to_tokens_for_custom_keyword!($ident);
+ impl_clone_for_custom_keyword!($ident);
+ impl_extra_traits_for_custom_keyword!($ident);
+ };
+}
+
+// Not public API.
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_parse_for_custom_keyword {
+ ($ident:ident) => {
+ // For peek.
+ impl $crate::token::CustomToken for $ident {
+ fn peek(cursor: $crate::buffer::Cursor) -> $crate::export::bool {
+ if let Some((ident, _rest)) = cursor.ident() {
+ ident == stringify!($ident)
+ } else {
+ false
+ }
+ }
+
+ fn display() -> &'static $crate::export::str {
+ concat!("`", stringify!($ident), "`")
+ }
+ }
+
+ impl $crate::parse::Parse for $ident {
+ fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
+ input.step(|cursor| {
+ if let $crate::export::Some((ident, rest)) = cursor.ident() {
+ if ident == stringify!($ident) {
+ return $crate::export::Ok(($ident { span: ident.span() }, rest));
+ }
+ }
+ $crate::export::Err(cursor.error(concat!(
+ "expected `",
+ stringify!($ident),
+ "`"
+ )))
+ })
+ }
+ }
+ };
+}
+
+// Not public API.
+#[cfg(not(feature = "parsing"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_parse_for_custom_keyword {
+ ($ident:ident) => {};
+}
+
+// Not public API.
+#[cfg(feature = "printing")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_to_tokens_for_custom_keyword {
+ ($ident:ident) => {
+ impl $crate::export::ToTokens for $ident {
+ fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
+ let ident = $crate::Ident::new(stringify!($ident), self.span);
+ $crate::export::TokenStreamExt::append(tokens, ident);
+ }
+ }
+ };
+}
+
+// Not public API.
+#[cfg(not(feature = "printing"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_to_tokens_for_custom_keyword {
+ ($ident:ident) => {};
+}
+
+// Not public API.
+#[cfg(feature = "clone-impls")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_clone_for_custom_keyword {
+ ($ident:ident) => {
+ impl $crate::export::Copy for $ident {}
+
+ impl $crate::export::Clone for $ident {
+ fn clone(&self) -> Self {
+ *self
+ }
+ }
+ };
+}
+
+// Not public API.
+#[cfg(not(feature = "clone-impls"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_clone_for_custom_keyword {
+ ($ident:ident) => {};
+}
+
+// Not public API.
+#[cfg(feature = "extra-traits")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_extra_traits_for_custom_keyword {
+ ($ident:ident) => {
+ impl $crate::export::Debug for $ident {
+ fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
+ $crate::export::Formatter::write_str(
+ f,
+ concat!("Keyword [", stringify!($ident), "]"),
+ )
+ }
+ }
+
+ impl $crate::export::Eq for $ident {}
+
+ impl $crate::export::PartialEq for $ident {
+ fn eq(&self, _other: &Self) -> $crate::export::bool {
+ true
+ }
+ }
+
+ impl $crate::export::Hash for $ident {
+ fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
+ }
+ };
+}
+
+// Not public API.
+#[cfg(not(feature = "extra-traits"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_extra_traits_for_custom_keyword {
+ ($ident:ident) => {};
+}
diff --git a/syn/src/custom_punctuation.rs b/syn/src/custom_punctuation.rs
new file mode 100644
index 0000000..29fa448
--- /dev/null
+++ b/syn/src/custom_punctuation.rs
@@ -0,0 +1,309 @@
+/// Define a type that supports parsing and printing a multi-character symbol
+/// as if it were a punctuation token.
+///
+/// # Usage
+///
+/// ```
+/// syn::custom_punctuation!(LeftRightArrow, <=>);
+/// ```
+///
+/// The generated syntax tree node supports the following operations just like
+/// any built-in punctuation token.
+///
+/// - [Peeking] — `input.peek(LeftRightArrow)`
+///
+/// - [Parsing] — `input.parse::<LeftRightArrow>()?`
+///
+/// - [Printing] — `quote!( ... #lrarrow ... )`
+///
+/// - Construction from a [`Span`] — `let lrarrow = LeftRightArrow(sp)`
+///
+/// - Construction from multiple [`Span`] — `let lrarrow = LeftRightArrow([sp, sp, sp])`
+///
+/// - Field access to its spans — `let spans = lrarrow.spans`
+///
+/// [Peeking]: parse::ParseBuffer::peek
+/// [Parsing]: parse::ParseBuffer::parse
+/// [Printing]: quote::ToTokens
+/// [`Span`]: proc_macro2::Span
+///
+/// # Example
+///
+/// ```
+/// use proc_macro2::{TokenStream, TokenTree};
+/// use syn::parse::{Parse, ParseStream, Peek, Result};
+/// use syn::punctuated::Punctuated;
+/// use syn::Expr;
+///
+/// syn::custom_punctuation!(PathSeparator, </>);
+///
+/// // expr </> expr </> expr ...
+/// struct PathSegments {
+/// segments: Punctuated<Expr, PathSeparator>,
+/// }
+///
+/// impl Parse for PathSegments {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// let mut segments = Punctuated::new();
+///
+/// let first = parse_until(input, PathSeparator)?;
+/// segments.push_value(syn::parse2(first)?);
+///
+/// while input.peek(PathSeparator) {
+/// segments.push_punct(input.parse()?);
+///
+/// let next = parse_until(input, PathSeparator)?;
+/// segments.push_value(syn::parse2(next)?);
+/// }
+///
+/// Ok(PathSegments { segments })
+/// }
+/// }
+///
+/// fn parse_until<E: Peek>(input: ParseStream, end: E) -> Result<TokenStream> {
+/// let mut tokens = TokenStream::new();
+/// while !input.is_empty() && !input.peek(end) {
+/// let next: TokenTree = input.parse()?;
+/// tokens.extend(Some(next));
+/// }
+/// Ok(tokens)
+/// }
+///
+/// fn main() {
+/// let input = r#" a::b </> c::d::e "#;
+/// let _: PathSegments = syn::parse_str(input).unwrap();
+/// }
+/// ```
+#[macro_export(local_inner_macros)]
+macro_rules! custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {
+ pub struct $ident {
+ pub spans: custom_punctuation_repr!($($tt)+),
+ }
+
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $ident<__S: $crate::export::IntoSpans<custom_punctuation_repr!($($tt)+)>>(
+ spans: __S,
+ ) -> $ident {
+ let _validate_len = 0 $(+ custom_punctuation_len!(strict, $tt))*;
+ $ident {
+ spans: $crate::export::IntoSpans::into_spans(spans)
+ }
+ }
+
+ impl $crate::export::Default for $ident {
+ fn default() -> Self {
+ $ident($crate::export::Span::call_site())
+ }
+ }
+
+ impl_parse_for_custom_punctuation!($ident, $($tt)+);
+ impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
+ impl_clone_for_custom_punctuation!($ident, $($tt)+);
+ impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
+ };
+}
+
+// Not public API.
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[macro_export(local_inner_macros)]
+macro_rules! impl_parse_for_custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {
+ impl $crate::token::CustomToken for $ident {
+ fn peek(cursor: $crate::buffer::Cursor) -> bool {
+ $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+))
+ }
+
+ fn display() -> &'static $crate::export::str {
+ custom_punctuation_concat!("`", stringify_punct!($($tt)+), "`")
+ }
+ }
+
+ impl $crate::parse::Parse for $ident {
+ fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
+ let spans: custom_punctuation_repr!($($tt)+) =
+ $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?;
+ Ok($ident(spans))
+ }
+ }
+ };
+}
+
+// Not public API.
+#[cfg(not(feature = "parsing"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_parse_for_custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {};
+}
+
+// Not public API.
+#[cfg(feature = "printing")]
+#[doc(hidden)]
+#[macro_export(local_inner_macros)]
+macro_rules! impl_to_tokens_for_custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {
+ impl $crate::export::ToTokens for $ident {
+ fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
+ $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens)
+ }
+ }
+ };
+}
+
+// Not public API.
+#[cfg(not(feature = "printing"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_to_tokens_for_custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {};
+}
+
+// Not public API.
+#[cfg(feature = "clone-impls")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_clone_for_custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {
+ impl $crate::export::Copy for $ident {}
+
+ impl $crate::export::Clone for $ident {
+ fn clone(&self) -> Self {
+ *self
+ }
+ }
+ };
+}
+
+// Not public API.
+#[cfg(not(feature = "clone-impls"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_clone_for_custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {};
+}
+
+// Not public API.
+#[cfg(feature = "extra-traits")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_extra_traits_for_custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {
+ impl $crate::export::Debug for $ident {
+ fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
+ $crate::export::Formatter::write_str(f, stringify!($ident))
+ }
+ }
+
+ impl $crate::export::Eq for $ident {}
+
+ impl $crate::export::PartialEq for $ident {
+ fn eq(&self, _other: &Self) -> $crate::export::bool {
+ true
+ }
+ }
+
+ impl $crate::export::Hash for $ident {
+ fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
+ }
+ };
+}
+
+// Not public API.
+#[cfg(not(feature = "extra-traits"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_extra_traits_for_custom_punctuation {
+ ($ident:ident, $($tt:tt)+) => {};
+}
+
+// Not public API.
+#[doc(hidden)]
+#[macro_export(local_inner_macros)]
+macro_rules! custom_punctuation_repr {
+ ($($tt:tt)+) => {
+ [$crate::export::Span; 0 $(+ custom_punctuation_len!(lenient, $tt))+]
+ };
+}
+
+// Not public API.
+#[doc(hidden)]
+#[macro_export(local_inner_macros)]
+#[rustfmt::skip]
+macro_rules! custom_punctuation_len {
+ ($mode:ident, +) => { 1 };
+ ($mode:ident, +=) => { 2 };
+ ($mode:ident, &) => { 1 };
+ ($mode:ident, &&) => { 2 };
+ ($mode:ident, &=) => { 2 };
+ ($mode:ident, @) => { 1 };
+ ($mode:ident, !) => { 1 };
+ ($mode:ident, ^) => { 1 };
+ ($mode:ident, ^=) => { 2 };
+ ($mode:ident, :) => { 1 };
+ ($mode:ident, ::) => { 2 };
+ ($mode:ident, ,) => { 1 };
+ ($mode:ident, /) => { 1 };
+ ($mode:ident, /=) => { 2 };
+ ($mode:ident, .) => { 1 };
+ ($mode:ident, ..) => { 2 };
+ ($mode:ident, ...) => { 3 };
+ ($mode:ident, ..=) => { 3 };
+ ($mode:ident, =) => { 1 };
+ ($mode:ident, ==) => { 2 };
+ ($mode:ident, >=) => { 2 };
+ ($mode:ident, >) => { 1 };
+ ($mode:ident, <=) => { 2 };
+ ($mode:ident, <) => { 1 };
+ ($mode:ident, *=) => { 2 };
+ ($mode:ident, !=) => { 2 };
+ ($mode:ident, |) => { 1 };
+ ($mode:ident, |=) => { 2 };
+ ($mode:ident, ||) => { 2 };
+ ($mode:ident, #) => { 1 };
+ ($mode:ident, ?) => { 1 };
+ ($mode:ident, ->) => { 2 };
+ ($mode:ident, <-) => { 2 };
+ ($mode:ident, %) => { 1 };
+ ($mode:ident, %=) => { 2 };
+ ($mode:ident, =>) => { 2 };
+ ($mode:ident, ;) => { 1 };
+ ($mode:ident, <<) => { 2 };
+ ($mode:ident, <<=) => { 3 };
+ ($mode:ident, >>) => { 2 };
+ ($mode:ident, >>=) => { 3 };
+ ($mode:ident, *) => { 1 };
+ ($mode:ident, -) => { 1 };
+ ($mode:ident, -=) => { 2 };
+ ($mode:ident, ~) => { 1 };
+ (lenient, $tt:tt) => { 0 };
+ (strict, $tt:tt) => {{ custom_punctuation_unexpected!($tt); 0 }};
+}
+
+// Not public API.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! custom_punctuation_unexpected {
+ () => {};
+}
+
+// Not public API.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! stringify_punct {
+ ($($tt:tt)+) => {
+ concat!($(stringify!($tt)),+)
+ };
+}
+
+// Not public API.
+// Without this, local_inner_macros breaks when looking for concat!
+#[doc(hidden)]
+#[macro_export]
+macro_rules! custom_punctuation_concat {
+ ($($tt:tt)*) => {
+ concat!($($tt)*)
+ };
+}
diff --git a/syn/src/data.rs b/syn/src/data.rs
new file mode 100644
index 0000000..184a79e
--- /dev/null
+++ b/syn/src/data.rs
@@ -0,0 +1,456 @@
+use super::*;
+use crate::punctuated::Punctuated;
+
+ast_struct! {
+ /// An enum variant.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Variant {
+ /// Attributes tagged on the variant.
+ pub attrs: Vec<Attribute>,
+
+ /// Name of the variant.
+ pub ident: Ident,
+
+ /// Content stored in the variant.
+ pub fields: Fields,
+
+ /// Explicit discriminant: `Variant = 1`
+ pub discriminant: Option<(Token![=], Expr)>,
+ }
+}
+
+ast_enum_of_structs! {
+ /// Data stored within an enum variant or struct.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum Fields {
+ /// Named fields of a struct or struct variant such as `Point { x: f64,
+ /// y: f64 }`.
+ Named(FieldsNamed),
+
+ /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
+ Unnamed(FieldsUnnamed),
+
+ /// Unit struct or unit variant such as `None`.
+ Unit,
+ }
+}
+
+ast_struct! {
+ /// Named fields of a struct or struct variant such as `Point { x: f64,
+ /// y: f64 }`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct FieldsNamed {
+ pub brace_token: token::Brace,
+ pub named: Punctuated<Field, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct FieldsUnnamed {
+ pub paren_token: token::Paren,
+ pub unnamed: Punctuated<Field, Token![,]>,
+ }
+}
+
+impl Fields {
+ /// Get an iterator over the borrowed [`Field`] items in this object. This
+ /// iterator can be used to iterate over a named or unnamed struct or
+ /// variant's fields uniformly.
+ pub fn iter(&self) -> punctuated::Iter<Field> {
+ match self {
+ Fields::Unit => crate::punctuated::empty_punctuated_iter(),
+ Fields::Named(f) => f.named.iter(),
+ Fields::Unnamed(f) => f.unnamed.iter(),
+ }
+ }
+
+ /// Get an iterator over the mutably borrowed [`Field`] items in this
+ /// object. This iterator can be used to iterate over a named or unnamed
+ /// struct or variant's fields uniformly.
+ pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
+ match self {
+ Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(),
+ Fields::Named(f) => f.named.iter_mut(),
+ Fields::Unnamed(f) => f.unnamed.iter_mut(),
+ }
+ }
+
+ /// Returns the number of fields.
+ pub fn len(&self) -> usize {
+ match self {
+ Fields::Unit => 0,
+ Fields::Named(f) => f.named.len(),
+ Fields::Unnamed(f) => f.unnamed.len(),
+ }
+ }
+
+ /// Returns `true` if there are zero fields.
+ pub fn is_empty(&self) -> bool {
+ match self {
+ Fields::Unit => true,
+ Fields::Named(f) => f.named.is_empty(),
+ Fields::Unnamed(f) => f.unnamed.is_empty(),
+ }
+ }
+}
+
+impl IntoIterator for Fields {
+ type Item = Field;
+ type IntoIter = punctuated::IntoIter<Field>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ match self {
+ Fields::Unit => Punctuated::<Field, ()>::new().into_iter(),
+ Fields::Named(f) => f.named.into_iter(),
+ Fields::Unnamed(f) => f.unnamed.into_iter(),
+ }
+ }
+}
+
+impl<'a> IntoIterator for &'a Fields {
+ type Item = &'a Field;
+ type IntoIter = punctuated::Iter<'a, Field>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a> IntoIterator for &'a mut Fields {
+ type Item = &'a mut Field;
+ type IntoIter = punctuated::IterMut<'a, Field>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+ast_struct! {
+ /// A field of a struct or enum variant.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Field {
+ /// Attributes tagged on the field.
+ pub attrs: Vec<Attribute>,
+
+ /// Visibility of the field.
+ pub vis: Visibility,
+
+ /// Name of the field, if any.
+ ///
+ /// Fields of tuple structs have no names.
+ pub ident: Option<Ident>,
+
+ pub colon_token: Option<Token![:]>,
+
+ /// Type of the field.
+ pub ty: Type,
+ }
+}
+
+ast_enum_of_structs! {
+ /// The visibility level of an item: inherited or `pub` or
+ /// `pub(restricted)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum Visibility {
+ /// A public visibility level: `pub`.
+ Public(VisPublic),
+
+ /// A crate-level visibility: `crate`.
+ Crate(VisCrate),
+
+ /// A visibility level restricted to some path: `pub(self)` or
+ /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
+ Restricted(VisRestricted),
+
+ /// An inherited visibility, which usually means private.
+ Inherited,
+ }
+}
+
+ast_struct! {
+ /// A public visibility level: `pub`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct VisPublic {
+ pub pub_token: Token![pub],
+ }
+}
+
+ast_struct! {
+ /// A crate-level visibility: `crate`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct VisCrate {
+ pub crate_token: Token![crate],
+ }
+}
+
+ast_struct! {
+ /// A visibility level restricted to some path: `pub(self)` or
+ /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct VisRestricted {
+ pub pub_token: Token![pub],
+ pub paren_token: token::Paren,
+ pub in_token: Option<Token![in]>,
+ pub path: Box<Path>,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::ext::IdentExt;
+ use crate::parse::discouraged::Speculative;
+ use crate::parse::{Parse, ParseStream, Result};
+
+ impl Parse for Variant {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Variant {
+ attrs: input.call(Attribute::parse_outer)?,
+ ident: input.parse()?,
+ fields: {
+ if input.peek(token::Brace) {
+ Fields::Named(input.parse()?)
+ } else if input.peek(token::Paren) {
+ Fields::Unnamed(input.parse()?)
+ } else {
+ Fields::Unit
+ }
+ },
+ discriminant: {
+ if input.peek(Token![=]) {
+ let eq_token: Token![=] = input.parse()?;
+ let discriminant: Expr = input.parse()?;
+ Some((eq_token, discriminant))
+ } else {
+ None
+ }
+ },
+ })
+ }
+ }
+
+ impl Parse for FieldsNamed {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(FieldsNamed {
+ brace_token: braced!(content in input),
+ named: content.parse_terminated(Field::parse_named)?,
+ })
+ }
+ }
+
+ impl Parse for FieldsUnnamed {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(FieldsUnnamed {
+ paren_token: parenthesized!(content in input),
+ unnamed: content.parse_terminated(Field::parse_unnamed)?,
+ })
+ }
+ }
+
+ impl Field {
+ /// Parses a named (braced struct) field.
+ pub fn parse_named(input: ParseStream) -> Result<Self> {
+ Ok(Field {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ ident: Some(input.parse()?),
+ colon_token: Some(input.parse()?),
+ ty: input.parse()?,
+ })
+ }
+
+ /// Parses an unnamed (tuple struct) field.
+ pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
+ Ok(Field {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ ident: None,
+ colon_token: None,
+ ty: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for Visibility {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Token![pub]) {
+ Self::parse_pub(input)
+ } else if input.peek(Token![crate]) {
+ Self::parse_crate(input)
+ } else {
+ Ok(Visibility::Inherited)
+ }
+ }
+ }
+
+ impl Visibility {
+ fn parse_pub(input: ParseStream) -> Result<Self> {
+ let pub_token = input.parse::<Token![pub]>()?;
+
+ if input.peek(token::Paren) {
+ let ahead = input.fork();
+
+ let content;
+ let paren_token = parenthesized!(content in ahead);
+ if content.peek(Token![crate])
+ || content.peek(Token![self])
+ || content.peek(Token![super])
+ {
+ let path = content.call(Ident::parse_any)?;
+
+ // Ensure there are no additional tokens within `content`.
+ // Without explicitly checking, we may misinterpret a tuple
+ // field as a restricted visibility, causing a parse error.
+ // e.g. `pub (crate::A, crate::B)` (Issue #720).
+ if content.is_empty() {
+ input.advance_to(&ahead);
+ return Ok(Visibility::Restricted(VisRestricted {
+ pub_token,
+ paren_token,
+ in_token: None,
+ path: Box::new(Path::from(path)),
+ }));
+ }
+ } else if content.peek(Token![in]) {
+ let in_token: Token![in] = content.parse()?;
+ let path = content.call(Path::parse_mod_style)?;
+
+ input.advance_to(&ahead);
+ return Ok(Visibility::Restricted(VisRestricted {
+ pub_token,
+ paren_token,
+ in_token: Some(in_token),
+ path: Box::new(path),
+ }));
+ }
+ }
+
+ Ok(Visibility::Public(VisPublic { pub_token }))
+ }
+
+ fn parse_crate(input: ParseStream) -> Result<Self> {
+ if input.peek2(Token![::]) {
+ Ok(Visibility::Inherited)
+ } else {
+ Ok(Visibility::Crate(VisCrate {
+ crate_token: input.parse()?,
+ }))
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ use crate::print::TokensOrDefault;
+
+ impl ToTokens for Variant {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.ident.to_tokens(tokens);
+ self.fields.to_tokens(tokens);
+ if let Some((eq_token, disc)) = &self.discriminant {
+ eq_token.to_tokens(tokens);
+ disc.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for FieldsNamed {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.brace_token.surround(tokens, |tokens| {
+ self.named.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for FieldsUnnamed {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.unnamed.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for Field {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.vis.to_tokens(tokens);
+ if let Some(ident) = &self.ident {
+ ident.to_tokens(tokens);
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ }
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for VisPublic {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.pub_token.to_tokens(tokens)
+ }
+ }
+
+ impl ToTokens for VisCrate {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.crate_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for VisRestricted {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.pub_token.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ // TODO: If we have a path which is not "self" or "super" or
+ // "crate", automatically add the "in" token.
+ self.in_token.to_tokens(tokens);
+ self.path.to_tokens(tokens);
+ });
+ }
+ }
+}
diff --git a/syn/src/derive.rs b/syn/src/derive.rs
new file mode 100644
index 0000000..8cb9cf7
--- /dev/null
+++ b/syn/src/derive.rs
@@ -0,0 +1,273 @@
+use super::*;
+use crate::punctuated::Punctuated;
+
+ast_struct! {
+ /// Data structure sent to a `proc_macro_derive` macro.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` feature.*
+ pub struct DeriveInput {
+ /// Attributes tagged on the whole struct or enum.
+ pub attrs: Vec<Attribute>,
+
+ /// Visibility of the struct or enum.
+ pub vis: Visibility,
+
+ /// Name of the struct or enum.
+ pub ident: Ident,
+
+ /// Generics required to complete the definition.
+ pub generics: Generics,
+
+ /// Data within the struct or enum.
+ pub data: Data,
+ }
+}
+
+ast_enum_of_structs! {
+ /// The storage of a struct, enum or union data structure.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum Data {
+ /// A struct input to a `proc_macro_derive` macro.
+ Struct(DataStruct),
+
+ /// An enum input to a `proc_macro_derive` macro.
+ Enum(DataEnum),
+
+ /// An untagged union input to a `proc_macro_derive` macro.
+ Union(DataUnion),
+ }
+
+ do_not_generate_to_tokens
+}
+
+ast_struct! {
+ /// A struct input to a `proc_macro_derive` macro.
+ ///
+ /// *This type is available if Syn is built with the `"derive"`
+ /// feature.*
+ pub struct DataStruct {
+ pub struct_token: Token![struct],
+ pub fields: Fields,
+ pub semi_token: Option<Token![;]>,
+ }
+}
+
+ast_struct! {
+ /// An enum input to a `proc_macro_derive` macro.
+ ///
+ /// *This type is available if Syn is built with the `"derive"`
+ /// feature.*
+ pub struct DataEnum {
+ pub enum_token: Token![enum],
+ pub brace_token: token::Brace,
+ pub variants: Punctuated<Variant, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// An untagged union input to a `proc_macro_derive` macro.
+ ///
+ /// *This type is available if Syn is built with the `"derive"`
+ /// feature.*
+ pub struct DataUnion {
+ pub union_token: Token![union],
+ pub fields: FieldsNamed,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::parse::{Parse, ParseStream, Result};
+
+ impl Parse for DeriveInput {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis = input.parse::<Visibility>()?;
+
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![struct]) {
+ let struct_token = input.parse::<Token![struct]>()?;
+ let ident = input.parse::<Ident>()?;
+ let generics = input.parse::<Generics>()?;
+ let (where_clause, fields, semi) = data_struct(input)?;
+ Ok(DeriveInput {
+ attrs,
+ vis,
+ ident,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ data: Data::Struct(DataStruct {
+ struct_token,
+ fields,
+ semi_token: semi,
+ }),
+ })
+ } else if lookahead.peek(Token![enum]) {
+ let enum_token = input.parse::<Token![enum]>()?;
+ let ident = input.parse::<Ident>()?;
+ let generics = input.parse::<Generics>()?;
+ let (where_clause, brace, variants) = data_enum(input)?;
+ Ok(DeriveInput {
+ attrs,
+ vis,
+ ident,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ data: Data::Enum(DataEnum {
+ enum_token,
+ brace_token: brace,
+ variants,
+ }),
+ })
+ } else if lookahead.peek(Token![union]) {
+ let union_token = input.parse::<Token![union]>()?;
+ let ident = input.parse::<Ident>()?;
+ let generics = input.parse::<Generics>()?;
+ let (where_clause, fields) = data_union(input)?;
+ Ok(DeriveInput {
+ attrs,
+ vis,
+ ident,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ data: Data::Union(DataUnion {
+ union_token,
+ fields,
+ }),
+ })
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ pub fn data_struct(
+ input: ParseStream,
+ ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> {
+ let mut lookahead = input.lookahead1();
+ let mut where_clause = None;
+ if lookahead.peek(Token![where]) {
+ where_clause = Some(input.parse()?);
+ lookahead = input.lookahead1();
+ }
+
+ if where_clause.is_none() && lookahead.peek(token::Paren) {
+ let fields = input.parse()?;
+
+ lookahead = input.lookahead1();
+ if lookahead.peek(Token![where]) {
+ where_clause = Some(input.parse()?);
+ lookahead = input.lookahead1();
+ }
+
+ if lookahead.peek(Token![;]) {
+ let semi = input.parse()?;
+ Ok((where_clause, Fields::Unnamed(fields), Some(semi)))
+ } else {
+ Err(lookahead.error())
+ }
+ } else if lookahead.peek(token::Brace) {
+ let fields = input.parse()?;
+ Ok((where_clause, Fields::Named(fields), None))
+ } else if lookahead.peek(Token![;]) {
+ let semi = input.parse()?;
+ Ok((where_clause, Fields::Unit, Some(semi)))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+
+ pub fn data_enum(
+ input: ParseStream,
+ ) -> Result<(
+ Option<WhereClause>,
+ token::Brace,
+ Punctuated<Variant, Token![,]>,
+ )> {
+ let where_clause = input.parse()?;
+
+ let content;
+ let brace = braced!(content in input);
+ let variants = content.parse_terminated(Variant::parse)?;
+
+ Ok((where_clause, brace, variants))
+ }
+
+ pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
+ let where_clause = input.parse()?;
+ let fields = input.parse()?;
+ Ok((where_clause, fields))
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ use crate::attr::FilterAttrs;
+ use crate::print::TokensOrDefault;
+
+ impl ToTokens for DeriveInput {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ for attr in self.attrs.outer() {
+ attr.to_tokens(tokens);
+ }
+ self.vis.to_tokens(tokens);
+ match &self.data {
+ Data::Struct(d) => d.struct_token.to_tokens(tokens),
+ Data::Enum(d) => d.enum_token.to_tokens(tokens),
+ Data::Union(d) => d.union_token.to_tokens(tokens),
+ }
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ match &self.data {
+ Data::Struct(data) => match &data.fields {
+ Fields::Named(fields) => {
+ self.generics.where_clause.to_tokens(tokens);
+ fields.to_tokens(tokens);
+ }
+ Fields::Unnamed(fields) => {
+ fields.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ TokensOrDefault(&data.semi_token).to_tokens(tokens);
+ }
+ Fields::Unit => {
+ self.generics.where_clause.to_tokens(tokens);
+ TokensOrDefault(&data.semi_token).to_tokens(tokens);
+ }
+ },
+ Data::Enum(data) => {
+ self.generics.where_clause.to_tokens(tokens);
+ data.brace_token.surround(tokens, |tokens| {
+ data.variants.to_tokens(tokens);
+ });
+ }
+ Data::Union(data) => {
+ self.generics.where_clause.to_tokens(tokens);
+ data.fields.to_tokens(tokens);
+ }
+ }
+ }
+ }
+}
diff --git a/syn/src/discouraged.rs b/syn/src/discouraged.rs
new file mode 100644
index 0000000..29d1006
--- /dev/null
+++ b/syn/src/discouraged.rs
@@ -0,0 +1,195 @@
+//! Extensions to the parsing API with niche applicability.
+
+use super::*;
+
+/// Extensions to the `ParseStream` API to support speculative parsing.
+pub trait Speculative {
+ /// Advance this parse stream to the position of a forked parse stream.
+ ///
+ /// This is the opposite operation to [`ParseStream::fork`]. You can fork a
+ /// parse stream, perform some speculative parsing, then join the original
+ /// stream to the fork to "commit" the parsing from the fork to the main
+ /// stream.
+ ///
+ /// If you can avoid doing this, you should, as it limits the ability to
+ /// generate useful errors. That said, it is often the only way to parse
+ /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem
+ /// is that when the fork fails to parse an `A`, it's impossible to tell
+ /// whether that was because of a syntax error and the user meant to provide
+ /// an `A`, or that the `A`s are finished and its time to start parsing
+ /// `B`s. Use with care.
+ ///
+ /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by
+ /// parsing `B*` and removing the leading members of `A` from the
+ /// repetition, bypassing the need to involve the downsides associated with
+ /// speculative parsing.
+ ///
+ /// [`ParseStream::fork`]: ParseBuffer::fork
+ ///
+ /// # Example
+ ///
+ /// There has been chatter about the possibility of making the colons in the
+ /// turbofish syntax like `path::to::<T>` no longer required by accepting
+ /// `path::to<T>` in expression position. Specifically, according to [RFC
+ /// 2544], [`PathSegment`] parsing should always try to consume a following
+ /// `<` token as the start of generic arguments, and reset to the `<` if
+ /// that fails (e.g. the token is acting as a less-than operator).
+ ///
+ /// This is the exact kind of parsing behavior which requires the "fork,
+ /// try, commit" behavior that [`ParseStream::fork`] discourages. With
+ /// `advance_to`, we can avoid having to parse the speculatively parsed
+ /// content a second time.
+ ///
+ /// This change in behavior can be implemented in syn by replacing just the
+ /// `Parse` implementation for `PathSegment`:
+ ///
+ /// ```
+ /// # use syn::ext::IdentExt;
+ /// use syn::parse::discouraged::Speculative;
+ /// # use syn::parse::{Parse, ParseStream};
+ /// # use syn::{Ident, PathArguments, Result, Token};
+ ///
+ /// pub struct PathSegment {
+ /// pub ident: Ident,
+ /// pub arguments: PathArguments,
+ /// }
+ /// #
+ /// # impl<T> From<T> for PathSegment
+ /// # where
+ /// # T: Into<Ident>,
+ /// # {
+ /// # fn from(ident: T) -> Self {
+ /// # PathSegment {
+ /// # ident: ident.into(),
+ /// # arguments: PathArguments::None,
+ /// # }
+ /// # }
+ /// # }
+ ///
+ /// impl Parse for PathSegment {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// if input.peek(Token![super])
+ /// || input.peek(Token![self])
+ /// || input.peek(Token![Self])
+ /// || input.peek(Token![crate])
+ /// || input.peek(Token![extern])
+ /// {
+ /// let ident = input.call(Ident::parse_any)?;
+ /// return Ok(PathSegment::from(ident));
+ /// }
+ ///
+ /// let ident = input.parse()?;
+ /// if input.peek(Token![::]) && input.peek3(Token![<]) {
+ /// return Ok(PathSegment {
+ /// ident,
+ /// arguments: PathArguments::AngleBracketed(input.parse()?),
+ /// });
+ /// }
+ /// if input.peek(Token![<]) && !input.peek(Token![<=]) {
+ /// let fork = input.fork();
+ /// if let Ok(arguments) = fork.parse() {
+ /// input.advance_to(&fork);
+ /// return Ok(PathSegment {
+ /// ident,
+ /// arguments: PathArguments::AngleBracketed(arguments),
+ /// });
+ /// }
+ /// }
+ /// Ok(PathSegment::from(ident))
+ /// }
+ /// }
+ ///
+ /// # syn::parse_str::<PathSegment>("a<b,c>").unwrap();
+ /// ```
+ ///
+ /// # Drawbacks
+ ///
+ /// The main drawback of this style of speculative parsing is in error
+ /// presentation. Even if the lookahead is the "correct" parse, the error
+ /// that is shown is that of the "fallback" parse. To use the same example
+ /// as the turbofish above, take the following unfinished "turbofish":
+ ///
+ /// ```text
+ /// let _ = f<&'a fn(), for<'a> serde::>();
+ /// ```
+ ///
+ /// If this is parsed as generic arguments, we can provide the error message
+ ///
+ /// ```text
+ /// error: expected identifier
+ /// --> src.rs:L:C
+ /// |
+ /// L | let _ = f<&'a fn(), for<'a> serde::>();
+ /// | ^
+ /// ```
+ ///
+ /// but if parsed using the above speculative parsing, it falls back to
+ /// assuming that the `<` is a less-than when it fails to parse the generic
+ /// arguments, and tries to interpret the `&'a` as the start of a labelled
+ /// loop, resulting in the much less helpful error
+ ///
+ /// ```text
+ /// error: expected `:`
+ /// --> src.rs:L:C
+ /// |
+ /// L | let _ = f<&'a fn(), for<'a> serde::>();
+ /// | ^^
+ /// ```
+ ///
+ /// This can be mitigated with various heuristics (two examples: show both
+ /// forks' parse errors, or show the one that consumed more tokens), but
+ /// when you can control the grammar, sticking to something that can be
+ /// parsed LL(3) and without the LL(*) speculative parsing this makes
+ /// possible, displaying reasonable errors becomes much more simple.
+ ///
+ /// [RFC 2544]: https://github.com/rust-lang/rfcs/pull/2544
+ /// [`PathSegment`]: crate::PathSegment
+ ///
+ /// # Performance
+ ///
+ /// This method performs a cheap fixed amount of work that does not depend
+ /// on how far apart the two streams are positioned.
+ ///
+ /// # Panics
+ ///
+ /// The forked stream in the argument of `advance_to` must have been
+ /// obtained by forking `self`. Attempting to advance to any other stream
+ /// will cause a panic.
+ fn advance_to(&self, fork: &Self);
+}
+
+impl<'a> Speculative for ParseBuffer<'a> {
+ fn advance_to(&self, fork: &Self) {
+ if !crate::buffer::same_scope(self.cursor(), fork.cursor()) {
+ panic!("Fork was not derived from the advancing parse stream");
+ }
+
+ let (self_unexp, self_sp) = inner_unexpected(self);
+ let (fork_unexp, fork_sp) = inner_unexpected(fork);
+ if !Rc::ptr_eq(&self_unexp, &fork_unexp) {
+ match (fork_sp, self_sp) {
+ // Unexpected set on the fork, but not on `self`, copy it over.
+ (Some(span), None) => {
+ self_unexp.set(Unexpected::Some(span));
+ }
+ // Unexpected unset. Use chain to propagate errors from fork.
+ (None, None) => {
+ fork_unexp.set(Unexpected::Chain(self_unexp));
+
+ // Ensure toplevel 'unexpected' tokens from the fork don't
+ // bubble up the chain by replacing the root `unexpected`
+ // pointer, only 'unexpected' tokens from existing group
+ // parsers should bubble.
+ fork.unexpected
+ .set(Some(Rc::new(Cell::new(Unexpected::None))));
+ }
+ // Unexpected has been set on `self`. No changes needed.
+ (_, Some(_)) => {}
+ }
+ }
+
+ // See comment on `cell` in the struct definition.
+ self.cell
+ .set(unsafe { mem::transmute::<Cursor, Cursor<'static>>(fork.cursor()) })
+ }
+}
diff --git a/syn/src/error.rs b/syn/src/error.rs
new file mode 100644
index 0000000..146d652
--- /dev/null
+++ b/syn/src/error.rs
@@ -0,0 +1,357 @@
+use std;
+use std::fmt::{self, Debug, Display};
+use std::iter::FromIterator;
+use std::slice;
+use std::vec;
+
+use proc_macro2::{
+ Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
+};
+#[cfg(feature = "printing")]
+use quote::ToTokens;
+
+#[cfg(feature = "parsing")]
+use crate::buffer::Cursor;
+use crate::thread::ThreadBound;
+
+/// The result of a Syn parser.
+pub type Result<T> = std::result::Result<T, Error>;
+
+/// Error returned when a Syn parser cannot parse the input tokens.
+///
+/// # Error reporting in proc macros
+///
+/// The correct way to report errors back to the compiler from a procedural
+/// macro is by emitting an appropriately spanned invocation of
+/// [`compile_error!`] in the generated code. This produces a better diagnostic
+/// message than simply panicking the macro.
+///
+/// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
+///
+/// When parsing macro input, the [`parse_macro_input!`] macro handles the
+/// conversion to `compile_error!` automatically.
+///
+/// ```
+/// extern crate proc_macro;
+///
+/// use proc_macro::TokenStream;
+/// use syn::{parse_macro_input, AttributeArgs, ItemFn};
+///
+/// # const IGNORE: &str = stringify! {
+/// #[proc_macro_attribute]
+/// # };
+/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream {
+/// let args = parse_macro_input!(args as AttributeArgs);
+/// let input = parse_macro_input!(input as ItemFn);
+///
+/// /* ... */
+/// # TokenStream::new()
+/// }
+/// ```
+///
+/// For errors that arise later than the initial parsing stage, the
+/// [`.to_compile_error()`] method can be used to perform an explicit conversion
+/// to `compile_error!`.
+///
+/// [`.to_compile_error()`]: Error::to_compile_error
+///
+/// ```
+/// # extern crate proc_macro;
+/// #
+/// # use proc_macro::TokenStream;
+/// # use syn::{parse_macro_input, DeriveInput};
+/// #
+/// # const IGNORE: &str = stringify! {
+/// #[proc_macro_derive(MyDerive)]
+/// # };
+/// pub fn my_derive(input: TokenStream) -> TokenStream {
+/// let input = parse_macro_input!(input as DeriveInput);
+///
+/// // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream>
+/// expand::my_derive(input)
+/// .unwrap_or_else(|err| err.to_compile_error())
+/// .into()
+/// }
+/// #
+/// # mod expand {
+/// # use proc_macro2::TokenStream;
+/// # use syn::{DeriveInput, Result};
+/// #
+/// # pub fn my_derive(input: DeriveInput) -> Result<TokenStream> {
+/// # unimplemented!()
+/// # }
+/// # }
+/// ```
+#[derive(Clone)]
+pub struct Error {
+ messages: Vec<ErrorMessage>,
+}
+
+struct ErrorMessage {
+ // Span is implemented as an index into a thread-local interner to keep the
+ // size small. It is not safe to access from a different thread. We want
+ // errors to be Send and Sync to play nicely with the Failure crate, so pin
+ // the span we're given to its original thread and assume it is
+ // Span::call_site if accessed from any other thread.
+ start_span: ThreadBound<Span>,
+ end_span: ThreadBound<Span>,
+ message: String,
+}
+
+#[cfg(test)]
+struct _Test
+where
+ Error: Send + Sync;
+
+impl Error {
+ /// Usually the [`ParseStream::error`] method will be used instead, which
+ /// automatically uses the correct span from the current position of the
+ /// parse stream.
+ ///
+ /// Use `Error::new` when the error needs to be triggered on some span other
+ /// than where the parse stream is currently positioned.
+ ///
+ /// [`ParseStream::error`]: crate::parse::ParseBuffer::error
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{Error, Ident, LitStr, Result, Token};
+ /// use syn::parse::ParseStream;
+ ///
+ /// // Parses input that looks like `name = "string"` where the key must be
+ /// // the identifier `name` and the value may be any string literal.
+ /// // Returns the string literal.
+ /// fn parse_name(input: ParseStream) -> Result<LitStr> {
+ /// let name_token: Ident = input.parse()?;
+ /// if name_token != "name" {
+ /// // Trigger an error not on the current position of the stream,
+ /// // but on the position of the unexpected identifier.
+ /// return Err(Error::new(name_token.span(), "expected `name`"));
+ /// }
+ /// input.parse::<Token![=]>()?;
+ /// let s: LitStr = input.parse()?;
+ /// Ok(s)
+ /// }
+ /// ```
+ pub fn new<T: Display>(span: Span, message: T) -> Self {
+ Error {
+ messages: vec![ErrorMessage {
+ start_span: ThreadBound::new(span),
+ end_span: ThreadBound::new(span),
+ message: message.to_string(),
+ }],
+ }
+ }
+
+ /// Creates an error with the specified message spanning the given syntax
+ /// tree node.
+ ///
+ /// Unlike the `Error::new` constructor, this constructor takes an argument
+ /// `tokens` which is a syntax tree node. This allows the resulting `Error`
+ /// to attempt to span all tokens inside of `tokens`. While you would
+ /// typically be able to use the `Spanned` trait with the above `Error::new`
+ /// constructor, implementation limitations today mean that
+ /// `Error::new_spanned` may provide a higher-quality error message on
+ /// stable Rust.
+ ///
+ /// When in doubt it's recommended to stick to `Error::new` (or
+ /// `ParseStream::error`)!
+ #[cfg(feature = "printing")]
+ pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
+ let mut iter = tokens.into_token_stream().into_iter();
+ let start = iter.next().map_or_else(Span::call_site, |t| t.span());
+ let end = iter.last().map_or(start, |t| t.span());
+ Error {
+ messages: vec![ErrorMessage {
+ start_span: ThreadBound::new(start),
+ end_span: ThreadBound::new(end),
+ message: message.to_string(),
+ }],
+ }
+ }
+
+ /// The source location of the error.
+ ///
+ /// Spans are not thread-safe so this function returns `Span::call_site()`
+ /// if called from a different thread than the one on which the `Error` was
+ /// originally created.
+ pub fn span(&self) -> Span {
+ let start = match self.messages[0].start_span.get() {
+ Some(span) => *span,
+ None => return Span::call_site(),
+ };
+ let end = match self.messages[0].end_span.get() {
+ Some(span) => *span,
+ None => return Span::call_site(),
+ };
+ start.join(end).unwrap_or(start)
+ }
+
+ /// Render the error as an invocation of [`compile_error!`].
+ ///
+ /// The [`parse_macro_input!`] macro provides a convenient way to invoke
+ /// this method correctly in a procedural macro.
+ ///
+ /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html
+ pub fn to_compile_error(&self) -> TokenStream {
+ self.messages
+ .iter()
+ .map(ErrorMessage::to_compile_error)
+ .collect()
+ }
+
+ /// Add another error message to self such that when `to_compile_error()` is
+ /// called, both errors will be emitted together.
+ pub fn combine(&mut self, another: Error) {
+ self.messages.extend(another.messages)
+ }
+}
+
+impl ErrorMessage {
+ fn to_compile_error(&self) -> TokenStream {
+ let start = self
+ .start_span
+ .get()
+ .cloned()
+ .unwrap_or_else(Span::call_site);
+ let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
+
+ // compile_error!($message)
+ TokenStream::from_iter(vec![
+ TokenTree::Ident(Ident::new("compile_error", start)),
+ TokenTree::Punct({
+ let mut punct = Punct::new('!', Spacing::Alone);
+ punct.set_span(start);
+ punct
+ }),
+ TokenTree::Group({
+ let mut group = Group::new(Delimiter::Brace, {
+ TokenStream::from_iter(vec![TokenTree::Literal({
+ let mut string = Literal::string(&self.message);
+ string.set_span(end);
+ string
+ })])
+ });
+ group.set_span(end);
+ group
+ }),
+ ])
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
+ if cursor.eof() {
+ Error::new(scope, format!("unexpected end of input, {}", message))
+ } else {
+ let span = crate::buffer::open_span_of_group(cursor);
+ Error::new(span, message)
+ }
+}
+
+impl Debug for Error {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ if self.messages.len() == 1 {
+ formatter
+ .debug_tuple("Error")
+ .field(&self.messages[0])
+ .finish()
+ } else {
+ formatter
+ .debug_tuple("Error")
+ .field(&self.messages)
+ .finish()
+ }
+ }
+}
+
+impl Debug for ErrorMessage {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ Debug::fmt(&self.message, formatter)
+ }
+}
+
+impl Display for Error {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str(&self.messages[0].message)
+ }
+}
+
+impl Clone for ErrorMessage {
+ fn clone(&self) -> Self {
+ let start = self
+ .start_span
+ .get()
+ .cloned()
+ .unwrap_or_else(Span::call_site);
+ let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site);
+ ErrorMessage {
+ start_span: ThreadBound::new(start),
+ end_span: ThreadBound::new(end),
+ message: self.message.clone(),
+ }
+ }
+}
+
+impl std::error::Error for Error {
+ fn description(&self) -> &str {
+ "parse error"
+ }
+}
+
+impl From<LexError> for Error {
+ fn from(err: LexError) -> Self {
+ Error::new(Span::call_site(), format!("{:?}", err))
+ }
+}
+
+impl IntoIterator for Error {
+ type Item = Error;
+ type IntoIter = IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ IntoIter {
+ messages: self.messages.into_iter(),
+ }
+ }
+}
+
+pub struct IntoIter {
+ messages: vec::IntoIter<ErrorMessage>,
+}
+
+impl Iterator for IntoIter {
+ type Item = Error;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ Some(Error {
+ messages: vec![self.messages.next()?],
+ })
+ }
+}
+
+impl<'a> IntoIterator for &'a Error {
+ type Item = Error;
+ type IntoIter = Iter<'a>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Iter {
+ messages: self.messages.iter(),
+ }
+ }
+}
+
+pub struct Iter<'a> {
+ messages: slice::Iter<'a, ErrorMessage>,
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = Error;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ Some(Error {
+ messages: vec![self.messages.next()?.clone()],
+ })
+ }
+}
diff --git a/syn/src/export.rs b/syn/src/export.rs
new file mode 100644
index 0000000..37dc467
--- /dev/null
+++ b/syn/src/export.rs
@@ -0,0 +1,35 @@
+pub use std::clone::Clone;
+pub use std::cmp::{Eq, PartialEq};
+pub use std::convert::From;
+pub use std::default::Default;
+pub use std::fmt::{self, Debug, Formatter};
+pub use std::hash::{Hash, Hasher};
+pub use std::marker::Copy;
+pub use std::option::Option::{None, Some};
+pub use std::result::Result::{Err, Ok};
+
+#[cfg(feature = "printing")]
+pub extern crate quote;
+
+pub use proc_macro2::{Span, TokenStream as TokenStream2};
+
+pub use crate::span::IntoSpans;
+
+#[cfg(all(
+ not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
+ feature = "proc-macro"
+))]
+pub use proc_macro::TokenStream;
+
+#[cfg(feature = "printing")]
+pub use quote::{ToTokens, TokenStreamExt};
+
+#[allow(non_camel_case_types)]
+pub type bool = help::Bool;
+#[allow(non_camel_case_types)]
+pub type str = help::Str;
+
+mod help {
+ pub type Bool = bool;
+ pub type Str = str;
+}
diff --git a/syn/src/expr.rs b/syn/src/expr.rs
new file mode 100644
index 0000000..603dc32
--- /dev/null
+++ b/syn/src/expr.rs
@@ -0,0 +1,3236 @@
+use super::*;
+use crate::punctuated::Punctuated;
+#[cfg(feature = "extra-traits")]
+use crate::tt::TokenStreamHelper;
+use proc_macro2::{Span, TokenStream};
+#[cfg(feature = "printing")]
+use quote::IdentFragment;
+#[cfg(feature = "printing")]
+use std::fmt::{self, Display};
+use std::hash::{Hash, Hasher};
+#[cfg(all(feature = "parsing", feature = "full"))]
+use std::mem;
+
+ast_enum_of_structs! {
+ /// A Rust expression.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enums
+ ///
+ /// This type is a syntax tree enum. In Syn this and other syntax tree enums
+ /// are designed to be traversed using the following rebinding idiom.
+ ///
+ /// ```
+ /// # use syn::Expr;
+ /// #
+ /// # fn example(expr: Expr) {
+ /// # const IGNORE: &str = stringify! {
+ /// let expr: Expr = /* ... */;
+ /// # };
+ /// match expr {
+ /// Expr::MethodCall(expr) => {
+ /// /* ... */
+ /// }
+ /// Expr::Cast(expr) => {
+ /// /* ... */
+ /// }
+ /// Expr::If(expr) => {
+ /// /* ... */
+ /// }
+ ///
+ /// /* ... */
+ /// # _ => {}
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// We begin with a variable `expr` of type `Expr` that has no fields
+ /// (because it is an enum), and by matching on it and rebinding a variable
+ /// with the same name `expr` we effectively imbue our variable with all of
+ /// the data fields provided by the variant that it turned out to be. So for
+ /// example above if we ended up in the `MethodCall` case then we get to use
+ /// `expr.receiver`, `expr.args` etc; if we ended up in the `If` case we get
+ /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`.
+ ///
+ /// This approach avoids repeating the variant names twice on every line.
+ ///
+ /// ```
+ /// # use syn::{Expr, ExprMethodCall};
+ /// #
+ /// # fn example(expr: Expr) {
+ /// // Repetitive; recommend not doing this.
+ /// match expr {
+ /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => {
+ /// # }
+ /// # _ => {}
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// In general, the name to which a syntax tree enum variant is bound should
+ /// be a suitable name for the complete syntax tree enum type.
+ ///
+ /// ```
+ /// # use syn::{Expr, ExprField};
+ /// #
+ /// # fn example(discriminant: ExprField) {
+ /// // Binding is called `base` which is the name I would use if I were
+ /// // assigning `*discriminant.base` without an `if let`.
+ /// if let Expr::Tuple(base) = *discriminant.base {
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// A sign that you may not be choosing the right variable names is if you
+ /// see names getting repeated in your code, like accessing
+ /// `receiver.receiver` or `pat.pat` or `cond.cond`.
+ pub enum Expr #manual_extra_traits {
+ /// A slice literal expression: `[a, b, c, d]`.
+ Array(ExprArray),
+
+ /// An assignment expression: `a = compute()`.
+ Assign(ExprAssign),
+
+ /// A compound assignment expression: `counter += 1`.
+ AssignOp(ExprAssignOp),
+
+ /// An async block: `async { ... }`.
+ Async(ExprAsync),
+
+ /// An await expression: `fut.await`.
+ Await(ExprAwait),
+
+ /// A binary operation: `a + b`, `a * b`.
+ Binary(ExprBinary),
+
+ /// A blocked scope: `{ ... }`.
+ Block(ExprBlock),
+
+ /// A box expression: `box f`.
+ Box(ExprBox),
+
+ /// A `break`, with an optional label to break and an optional
+ /// expression.
+ Break(ExprBreak),
+
+ /// A function call expression: `invoke(a, b)`.
+ Call(ExprCall),
+
+ /// A cast expression: `foo as f64`.
+ Cast(ExprCast),
+
+ /// A closure expression: `|a, b| a + b`.
+ Closure(ExprClosure),
+
+ /// A `continue`, with an optional label.
+ Continue(ExprContinue),
+
+ /// Access of a named struct field (`obj.k`) or unnamed tuple struct
+ /// field (`obj.0`).
+ Field(ExprField),
+
+ /// A for loop: `for pat in expr { ... }`.
+ ForLoop(ExprForLoop),
+
+ /// An expression contained within invisible delimiters.
+ ///
+ /// This variant is important for faithfully representing the precedence
+ /// of expressions and is related to `None`-delimited spans in a
+ /// `TokenStream`.
+ Group(ExprGroup),
+
+ /// An `if` expression with an optional `else` block: `if expr { ... }
+ /// else { ... }`.
+ ///
+ /// The `else` branch expression may only be an `If` or `Block`
+ /// expression, not any of the other types of expression.
+ If(ExprIf),
+
+ /// A square bracketed indexing expression: `vector[2]`.
+ Index(ExprIndex),
+
+ /// A `let` guard: `let Some(x) = opt`.
+ Let(ExprLet),
+
+ /// A literal in place of an expression: `1`, `"foo"`.
+ Lit(ExprLit),
+
+ /// Conditionless loop: `loop { ... }`.
+ Loop(ExprLoop),
+
+ /// A macro invocation expression: `format!("{}", q)`.
+ Macro(ExprMacro),
+
+ /// A `match` expression: `match n { Some(n) => {}, None => {} }`.
+ Match(ExprMatch),
+
+ /// A method call expression: `x.foo::<T>(a, b)`.
+ MethodCall(ExprMethodCall),
+
+ /// A parenthesized expression: `(a + b)`.
+ Paren(ExprParen),
+
+ /// A path like `std::mem::replace` possibly containing generic
+ /// parameters and a qualified self-type.
+ ///
+ /// A plain identifier like `x` is a path of length 1.
+ Path(ExprPath),
+
+ /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`.
+ Range(ExprRange),
+
+ /// A referencing operation: `&a` or `&mut a`.
+ Reference(ExprReference),
+
+ /// An array literal constructed from one repeated element: `[0u8; N]`.
+ Repeat(ExprRepeat),
+
+ /// A `return`, with an optional value to be returned.
+ Return(ExprReturn),
+
+ /// A struct literal expression: `Point { x: 1, y: 1 }`.
+ ///
+ /// The `rest` provides the value of the remaining fields as in `S { a:
+ /// 1, b: 1, ..rest }`.
+ Struct(ExprStruct),
+
+ /// A try-expression: `expr?`.
+ Try(ExprTry),
+
+ /// A try block: `try { ... }`.
+ TryBlock(ExprTryBlock),
+
+ /// A tuple expression: `(a, b, c, d)`.
+ Tuple(ExprTuple),
+
+ /// A type ascription expression: `foo: f64`.
+ Type(ExprType),
+
+ /// A unary operation: `!x`, `*x`.
+ Unary(ExprUnary),
+
+ /// An unsafe block: `unsafe { ... }`.
+ Unsafe(ExprUnsafe),
+
+ /// Tokens in expression position not interpreted by Syn.
+ Verbatim(TokenStream),
+
+ /// A while loop: `while expr { ... }`.
+ While(ExprWhile),
+
+ /// A yield expression: `yield expr`.
+ Yield(ExprYield),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// A slice literal expression: `[a, b, c, d]`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprArray #full {
+ pub attrs: Vec<Attribute>,
+ pub bracket_token: token::Bracket,
+ pub elems: Punctuated<Expr, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// An assignment expression: `a = compute()`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprAssign #full {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub eq_token: Token![=],
+ pub right: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A compound assignment expression: `counter += 1`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprAssignOp #full {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub op: BinOp,
+ pub right: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// An async block: `async { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprAsync #full {
+ pub attrs: Vec<Attribute>,
+ pub async_token: Token![async],
+ pub capture: Option<Token![move]>,
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// An await expression: `fut.await`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprAwait #full {
+ pub attrs: Vec<Attribute>,
+ pub base: Box<Expr>,
+ pub dot_token: Token![.],
+ pub await_token: token::Await,
+ }
+}
+
+ast_struct! {
+ /// A binary operation: `a + b`, `a * b`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprBinary {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub op: BinOp,
+ pub right: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A blocked scope: `{ ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprBlock #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// A box expression: `box f`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprBox #full {
+ pub attrs: Vec<Attribute>,
+ pub box_token: Token![box],
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A `break`, with an optional label to break and an optional
+ /// expression.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprBreak #full {
+ pub attrs: Vec<Attribute>,
+ pub break_token: Token![break],
+ pub label: Option<Lifetime>,
+ pub expr: Option<Box<Expr>>,
+ }
+}
+
+ast_struct! {
+ /// A function call expression: `invoke(a, b)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprCall {
+ pub attrs: Vec<Attribute>,
+ pub func: Box<Expr>,
+ pub paren_token: token::Paren,
+ pub args: Punctuated<Expr, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A cast expression: `foo as f64`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprCast {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub as_token: Token![as],
+ pub ty: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A closure expression: `|a, b| a + b`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprClosure #full {
+ pub attrs: Vec<Attribute>,
+ pub asyncness: Option<Token![async]>,
+ pub movability: Option<Token![static]>,
+ pub capture: Option<Token![move]>,
+ pub or1_token: Token![|],
+ pub inputs: Punctuated<Pat, Token![,]>,
+ pub or2_token: Token![|],
+ pub output: ReturnType,
+ pub body: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A `continue`, with an optional label.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprContinue #full {
+ pub attrs: Vec<Attribute>,
+ pub continue_token: Token![continue],
+ pub label: Option<Lifetime>,
+ }
+}
+
+ast_struct! {
+ /// Access of a named struct field (`obj.k`) or unnamed tuple struct
+ /// field (`obj.0`).
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprField {
+ pub attrs: Vec<Attribute>,
+ pub base: Box<Expr>,
+ pub dot_token: Token![.],
+ pub member: Member,
+ }
+}
+
+ast_struct! {
+ /// A for loop: `for pat in expr { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprForLoop #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub for_token: Token![for],
+ pub pat: Pat,
+ pub in_token: Token![in],
+ pub expr: Box<Expr>,
+ pub body: Block,
+ }
+}
+
+ast_struct! {
+ /// An expression contained within invisible delimiters.
+ ///
+ /// This variant is important for faithfully representing the precedence
+ /// of expressions and is related to `None`-delimited spans in a
+ /// `TokenStream`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprGroup #full {
+ pub attrs: Vec<Attribute>,
+ pub group_token: token::Group,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// An `if` expression with an optional `else` block: `if expr { ... }
+ /// else { ... }`.
+ ///
+ /// The `else` branch expression may only be an `If` or `Block`
+ /// expression, not any of the other types of expression.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprIf #full {
+ pub attrs: Vec<Attribute>,
+ pub if_token: Token![if],
+ pub cond: Box<Expr>,
+ pub then_branch: Block,
+ pub else_branch: Option<(Token![else], Box<Expr>)>,
+ }
+}
+
+ast_struct! {
+ /// A square bracketed indexing expression: `vector[2]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprIndex {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub bracket_token: token::Bracket,
+ pub index: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A `let` guard: `let Some(x) = opt`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprLet #full {
+ pub attrs: Vec<Attribute>,
+ pub let_token: Token![let],
+ pub pat: Pat,
+ pub eq_token: Token![=],
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A literal in place of an expression: `1`, `"foo"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprLit {
+ pub attrs: Vec<Attribute>,
+ pub lit: Lit,
+ }
+}
+
+ast_struct! {
+ /// Conditionless loop: `loop { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprLoop #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub loop_token: Token![loop],
+ pub body: Block,
+ }
+}
+
+ast_struct! {
+ /// A macro invocation expression: `format!("{}", q)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprMacro #full {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ }
+}
+
+ast_struct! {
+ /// A `match` expression: `match n { Some(n) => {}, None => {} }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprMatch #full {
+ pub attrs: Vec<Attribute>,
+ pub match_token: Token![match],
+ pub expr: Box<Expr>,
+ pub brace_token: token::Brace,
+ pub arms: Vec<Arm>,
+ }
+}
+
+ast_struct! {
+ /// A method call expression: `x.foo::<T>(a, b)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprMethodCall #full {
+ pub attrs: Vec<Attribute>,
+ pub receiver: Box<Expr>,
+ pub dot_token: Token![.],
+ pub method: Ident,
+ pub turbofish: Option<MethodTurbofish>,
+ pub paren_token: token::Paren,
+ pub args: Punctuated<Expr, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A parenthesized expression: `(a + b)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprParen {
+ pub attrs: Vec<Attribute>,
+ pub paren_token: token::Paren,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A path like `std::mem::replace` possibly containing generic
+ /// parameters and a qualified self-type.
+ ///
+ /// A plain identifier like `x` is a path of length 1.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprPath {
+ pub attrs: Vec<Attribute>,
+ pub qself: Option<QSelf>,
+ pub path: Path,
+ }
+}
+
+ast_struct! {
+ /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprRange #full {
+ pub attrs: Vec<Attribute>,
+ pub from: Option<Box<Expr>>,
+ pub limits: RangeLimits,
+ pub to: Option<Box<Expr>>,
+ }
+}
+
+ast_struct! {
+ /// A referencing operation: `&a` or `&mut a`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprReference #full {
+ pub attrs: Vec<Attribute>,
+ pub and_token: Token![&],
+ pub raw: Reserved,
+ pub mutability: Option<Token![mut]>,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// An array literal constructed from one repeated element: `[0u8; N]`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprRepeat #full {
+ pub attrs: Vec<Attribute>,
+ pub bracket_token: token::Bracket,
+ pub expr: Box<Expr>,
+ pub semi_token: Token![;],
+ pub len: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A `return`, with an optional value to be returned.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprReturn #full {
+ pub attrs: Vec<Attribute>,
+ pub return_token: Token![return],
+ pub expr: Option<Box<Expr>>,
+ }
+}
+
+ast_struct! {
+ /// A struct literal expression: `Point { x: 1, y: 1 }`.
+ ///
+ /// The `rest` provides the value of the remaining fields as in `S { a:
+ /// 1, b: 1, ..rest }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprStruct #full {
+ pub attrs: Vec<Attribute>,
+ pub path: Path,
+ pub brace_token: token::Brace,
+ pub fields: Punctuated<FieldValue, Token![,]>,
+ pub dot2_token: Option<Token![..]>,
+ pub rest: Option<Box<Expr>>,
+ }
+}
+
+ast_struct! {
+ /// A try-expression: `expr?`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprTry #full {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub question_token: Token![?],
+ }
+}
+
+ast_struct! {
+ /// A try block: `try { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprTryBlock #full {
+ pub attrs: Vec<Attribute>,
+ pub try_token: Token![try],
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// A tuple expression: `(a, b, c, d)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprTuple #full {
+ pub attrs: Vec<Attribute>,
+ pub paren_token: token::Paren,
+ pub elems: Punctuated<Expr, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A type ascription expression: `foo: f64`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprType #full {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A unary operation: `!x`, `*x`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ExprUnary {
+ pub attrs: Vec<Attribute>,
+ pub op: UnOp,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// An unsafe block: `unsafe { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprUnsafe #full {
+ pub attrs: Vec<Attribute>,
+ pub unsafe_token: Token![unsafe],
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// A while loop: `while expr { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprWhile #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub while_token: Token![while],
+ pub cond: Box<Expr>,
+ pub body: Block,
+ }
+}
+
+ast_struct! {
+ /// A yield expression: `yield expr`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ExprYield #full {
+ pub attrs: Vec<Attribute>,
+ pub yield_token: Token![yield],
+ pub expr: Option<Box<Expr>>,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Expr {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Expr {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Expr::Array(this), Expr::Array(other)) => this == other,
+ (Expr::Assign(this), Expr::Assign(other)) => this == other,
+ (Expr::AssignOp(this), Expr::AssignOp(other)) => this == other,
+ (Expr::Async(this), Expr::Async(other)) => this == other,
+ (Expr::Await(this), Expr::Await(other)) => this == other,
+ (Expr::Binary(this), Expr::Binary(other)) => this == other,
+ (Expr::Block(this), Expr::Block(other)) => this == other,
+ (Expr::Box(this), Expr::Box(other)) => this == other,
+ (Expr::Break(this), Expr::Break(other)) => this == other,
+ (Expr::Call(this), Expr::Call(other)) => this == other,
+ (Expr::Cast(this), Expr::Cast(other)) => this == other,
+ (Expr::Closure(this), Expr::Closure(other)) => this == other,
+ (Expr::Continue(this), Expr::Continue(other)) => this == other,
+ (Expr::Field(this), Expr::Field(other)) => this == other,
+ (Expr::ForLoop(this), Expr::ForLoop(other)) => this == other,
+ (Expr::Group(this), Expr::Group(other)) => this == other,
+ (Expr::If(this), Expr::If(other)) => this == other,
+ (Expr::Index(this), Expr::Index(other)) => this == other,
+ (Expr::Let(this), Expr::Let(other)) => this == other,
+ (Expr::Lit(this), Expr::Lit(other)) => this == other,
+ (Expr::Loop(this), Expr::Loop(other)) => this == other,
+ (Expr::Macro(this), Expr::Macro(other)) => this == other,
+ (Expr::Match(this), Expr::Match(other)) => this == other,
+ (Expr::MethodCall(this), Expr::MethodCall(other)) => this == other,
+ (Expr::Paren(this), Expr::Paren(other)) => this == other,
+ (Expr::Path(this), Expr::Path(other)) => this == other,
+ (Expr::Range(this), Expr::Range(other)) => this == other,
+ (Expr::Reference(this), Expr::Reference(other)) => this == other,
+ (Expr::Repeat(this), Expr::Repeat(other)) => this == other,
+ (Expr::Return(this), Expr::Return(other)) => this == other,
+ (Expr::Struct(this), Expr::Struct(other)) => this == other,
+ (Expr::Try(this), Expr::Try(other)) => this == other,
+ (Expr::TryBlock(this), Expr::TryBlock(other)) => this == other,
+ (Expr::Tuple(this), Expr::Tuple(other)) => this == other,
+ (Expr::Type(this), Expr::Type(other)) => this == other,
+ (Expr::Unary(this), Expr::Unary(other)) => this == other,
+ (Expr::Unsafe(this), Expr::Unsafe(other)) => this == other,
+ (Expr::Verbatim(this), Expr::Verbatim(other)) => {
+ TokenStreamHelper(this) == TokenStreamHelper(other)
+ }
+ (Expr::While(this), Expr::While(other)) => this == other,
+ (Expr::Yield(this), Expr::Yield(other)) => this == other,
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Expr {
+ fn hash<H>(&self, hash: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ Expr::Array(expr) => {
+ hash.write_u8(0);
+ expr.hash(hash);
+ }
+ Expr::Assign(expr) => {
+ hash.write_u8(1);
+ expr.hash(hash);
+ }
+ Expr::AssignOp(expr) => {
+ hash.write_u8(2);
+ expr.hash(hash);
+ }
+ Expr::Async(expr) => {
+ hash.write_u8(3);
+ expr.hash(hash);
+ }
+ Expr::Await(expr) => {
+ hash.write_u8(4);
+ expr.hash(hash);
+ }
+ Expr::Binary(expr) => {
+ hash.write_u8(5);
+ expr.hash(hash);
+ }
+ Expr::Block(expr) => {
+ hash.write_u8(6);
+ expr.hash(hash);
+ }
+ Expr::Box(expr) => {
+ hash.write_u8(7);
+ expr.hash(hash);
+ }
+ Expr::Break(expr) => {
+ hash.write_u8(8);
+ expr.hash(hash);
+ }
+ Expr::Call(expr) => {
+ hash.write_u8(9);
+ expr.hash(hash);
+ }
+ Expr::Cast(expr) => {
+ hash.write_u8(10);
+ expr.hash(hash);
+ }
+ Expr::Closure(expr) => {
+ hash.write_u8(11);
+ expr.hash(hash);
+ }
+ Expr::Continue(expr) => {
+ hash.write_u8(12);
+ expr.hash(hash);
+ }
+ Expr::Field(expr) => {
+ hash.write_u8(13);
+ expr.hash(hash);
+ }
+ Expr::ForLoop(expr) => {
+ hash.write_u8(14);
+ expr.hash(hash);
+ }
+ Expr::Group(expr) => {
+ hash.write_u8(15);
+ expr.hash(hash);
+ }
+ Expr::If(expr) => {
+ hash.write_u8(16);
+ expr.hash(hash);
+ }
+ Expr::Index(expr) => {
+ hash.write_u8(17);
+ expr.hash(hash);
+ }
+ Expr::Let(expr) => {
+ hash.write_u8(18);
+ expr.hash(hash);
+ }
+ Expr::Lit(expr) => {
+ hash.write_u8(19);
+ expr.hash(hash);
+ }
+ Expr::Loop(expr) => {
+ hash.write_u8(20);
+ expr.hash(hash);
+ }
+ Expr::Macro(expr) => {
+ hash.write_u8(21);
+ expr.hash(hash);
+ }
+ Expr::Match(expr) => {
+ hash.write_u8(22);
+ expr.hash(hash);
+ }
+ Expr::MethodCall(expr) => {
+ hash.write_u8(23);
+ expr.hash(hash);
+ }
+ Expr::Paren(expr) => {
+ hash.write_u8(24);
+ expr.hash(hash);
+ }
+ Expr::Path(expr) => {
+ hash.write_u8(25);
+ expr.hash(hash);
+ }
+ Expr::Range(expr) => {
+ hash.write_u8(26);
+ expr.hash(hash);
+ }
+ Expr::Reference(expr) => {
+ hash.write_u8(27);
+ expr.hash(hash);
+ }
+ Expr::Repeat(expr) => {
+ hash.write_u8(28);
+ expr.hash(hash);
+ }
+ Expr::Return(expr) => {
+ hash.write_u8(29);
+ expr.hash(hash);
+ }
+ Expr::Struct(expr) => {
+ hash.write_u8(30);
+ expr.hash(hash);
+ }
+ Expr::Try(expr) => {
+ hash.write_u8(31);
+ expr.hash(hash);
+ }
+ Expr::TryBlock(expr) => {
+ hash.write_u8(32);
+ expr.hash(hash);
+ }
+ Expr::Tuple(expr) => {
+ hash.write_u8(33);
+ expr.hash(hash);
+ }
+ Expr::Type(expr) => {
+ hash.write_u8(34);
+ expr.hash(hash);
+ }
+ Expr::Unary(expr) => {
+ hash.write_u8(35);
+ expr.hash(hash);
+ }
+ Expr::Unsafe(expr) => {
+ hash.write_u8(36);
+ expr.hash(hash);
+ }
+ Expr::Verbatim(expr) => {
+ hash.write_u8(37);
+ TokenStreamHelper(expr).hash(hash);
+ }
+ Expr::While(expr) => {
+ hash.write_u8(38);
+ expr.hash(hash);
+ }
+ Expr::Yield(expr) => {
+ hash.write_u8(39);
+ expr.hash(hash);
+ }
+ Expr::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+impl Expr {
+ #[cfg(all(feature = "parsing", feature = "full"))]
+ pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> {
+ match self {
+ Expr::Box(ExprBox { attrs, .. })
+ | Expr::Array(ExprArray { attrs, .. })
+ | Expr::Call(ExprCall { attrs, .. })
+ | Expr::MethodCall(ExprMethodCall { attrs, .. })
+ | Expr::Tuple(ExprTuple { attrs, .. })
+ | Expr::Binary(ExprBinary { attrs, .. })
+ | Expr::Unary(ExprUnary { attrs, .. })
+ | Expr::Lit(ExprLit { attrs, .. })
+ | Expr::Cast(ExprCast { attrs, .. })
+ | Expr::Type(ExprType { attrs, .. })
+ | Expr::Let(ExprLet { attrs, .. })
+ | Expr::If(ExprIf { attrs, .. })
+ | Expr::While(ExprWhile { attrs, .. })
+ | Expr::ForLoop(ExprForLoop { attrs, .. })
+ | Expr::Loop(ExprLoop { attrs, .. })
+ | Expr::Match(ExprMatch { attrs, .. })
+ | Expr::Closure(ExprClosure { attrs, .. })
+ | Expr::Unsafe(ExprUnsafe { attrs, .. })
+ | Expr::Block(ExprBlock { attrs, .. })
+ | Expr::Assign(ExprAssign { attrs, .. })
+ | Expr::AssignOp(ExprAssignOp { attrs, .. })
+ | Expr::Field(ExprField { attrs, .. })
+ | Expr::Index(ExprIndex { attrs, .. })
+ | Expr::Range(ExprRange { attrs, .. })
+ | Expr::Path(ExprPath { attrs, .. })
+ | Expr::Reference(ExprReference { attrs, .. })
+ | Expr::Break(ExprBreak { attrs, .. })
+ | Expr::Continue(ExprContinue { attrs, .. })
+ | Expr::Return(ExprReturn { attrs, .. })
+ | Expr::Macro(ExprMacro { attrs, .. })
+ | Expr::Struct(ExprStruct { attrs, .. })
+ | Expr::Repeat(ExprRepeat { attrs, .. })
+ | Expr::Paren(ExprParen { attrs, .. })
+ | Expr::Group(ExprGroup { attrs, .. })
+ | Expr::Try(ExprTry { attrs, .. })
+ | Expr::Async(ExprAsync { attrs, .. })
+ | Expr::Await(ExprAwait { attrs, .. })
+ | Expr::TryBlock(ExprTryBlock { attrs, .. })
+ | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new),
+ Expr::Verbatim(_) => Vec::new(),
+ Expr::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+ast_enum! {
+ /// A struct or tuple struct field accessed in a struct literal or field
+ /// expression.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[derive(Eq, PartialEq, Hash)]
+ pub enum Member #manual_extra_traits {
+ /// A named field like `self.x`.
+ Named(Ident),
+ /// An unnamed field like `self.0`.
+ Unnamed(Index),
+ }
+}
+
+#[cfg(feature = "printing")]
+impl IdentFragment for Member {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Member::Named(m) => Display::fmt(m, formatter),
+ Member::Unnamed(m) => Display::fmt(&m.index, formatter),
+ }
+ }
+
+ fn span(&self) -> Option<Span> {
+ match self {
+ Member::Named(m) => Some(m.span()),
+ Member::Unnamed(m) => Some(m.span),
+ }
+ }
+}
+
+ast_struct! {
+ /// The index of an unnamed tuple struct field.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Index #manual_extra_traits {
+ pub index: u32,
+ pub span: Span,
+ }
+}
+
+impl From<usize> for Index {
+ fn from(index: usize) -> Index {
+ assert!(index < u32::max_value() as usize);
+ Index {
+ index: index as u32,
+ span: Span::call_site(),
+ }
+ }
+}
+
+impl Eq for Index {}
+
+impl PartialEq for Index {
+ fn eq(&self, other: &Self) -> bool {
+ self.index == other.index
+ }
+}
+
+impl Hash for Index {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.index.hash(state);
+ }
+}
+
+#[cfg(feature = "printing")]
+impl IdentFragment for Index {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(&self.index, formatter)
+ }
+
+ fn span(&self) -> Option<Span> {
+ Some(self.span)
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ #[derive(Default)]
+ pub struct Reserved {
+ _private: (),
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// The `::<>` explicit type parameters passed to a method call:
+ /// `parse::<u64>()`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct MethodTurbofish {
+ pub colon2_token: Token![::],
+ pub lt_token: Token![<],
+ pub args: Punctuated<GenericMethodArgument, Token![,]>,
+ pub gt_token: Token![>],
+ }
+}
+
+#[cfg(feature = "full")]
+ast_enum! {
+ /// An individual generic argument to a method, like `T`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub enum GenericMethodArgument {
+ /// A type argument.
+ Type(Type),
+ /// A const expression. Must be inside of a block.
+ ///
+ /// NOTE: Identity expressions are represented as Type arguments, as
+ /// they are indistinguishable syntactically.
+ Const(Expr),
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A field-value pair in a struct literal.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct FieldValue {
+ /// Attributes tagged on the field.
+ pub attrs: Vec<Attribute>,
+
+ /// Name or index of the field.
+ pub member: Member,
+
+ /// The colon in `Struct { x: x }`. If written in shorthand like
+ /// `Struct { x }`, there is no colon.
+ pub colon_token: Option<Token![:]>,
+
+ /// Value of the field.
+ pub expr: Expr,
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A lifetime labeling a `for`, `while`, or `loop`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Label {
+ pub name: Lifetime,
+ pub colon_token: Token![:],
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// One arm of a `match` expression: `0...10 => { return true; }`.
+ ///
+ /// As in:
+ ///
+ /// ```
+ /// # fn f() -> bool {
+ /// # let n = 0;
+ /// match n {
+ /// 0...10 => {
+ /// return true;
+ /// }
+ /// // ...
+ /// # _ => {}
+ /// }
+ /// # false
+ /// # }
+ /// ```
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Arm {
+ pub attrs: Vec<Attribute>,
+ pub pat: Pat,
+ pub guard: Option<(Token![if], Box<Expr>)>,
+ pub fat_arrow_token: Token![=>],
+ pub body: Box<Expr>,
+ pub comma: Option<Token![,]>,
+ }
+}
+
+#[cfg(feature = "full")]
+ast_enum! {
+ /// Limit types of a range, inclusive or exclusive.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum RangeLimits {
+ /// Inclusive at the beginning, exclusive at the end.
+ HalfOpen(Token![..]),
+ /// Inclusive at the beginning and end.
+ Closed(Token![..=]),
+ }
+}
+
+#[cfg(any(feature = "parsing", feature = "printing"))]
+#[cfg(feature = "full")]
+pub(crate) fn requires_terminator(expr: &Expr) -> bool {
+ // see https://github.com/rust-lang/rust/blob/eb8f2586e/src/libsyntax/parse/classify.rs#L17-L37
+ match *expr {
+ Expr::Unsafe(..)
+ | Expr::Block(..)
+ | Expr::If(..)
+ | Expr::Match(..)
+ | Expr::While(..)
+ | Expr::Loop(..)
+ | Expr::ForLoop(..)
+ | Expr::Async(..)
+ | Expr::TryBlock(..) => false,
+ _ => true,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub(crate) mod parsing {
+ use super::*;
+
+ use crate::parse::discouraged::Speculative;
+ use crate::parse::{Parse, ParseStream, Result};
+ use crate::path;
+
+ // When we're parsing expressions which occur before blocks, like in an if
+ // statement's condition, we cannot parse a struct literal.
+ //
+ // Struct literals are ambiguous in certain positions
+ // https://github.com/rust-lang/rfcs/pull/92
+ #[derive(Copy, Clone)]
+ pub struct AllowStruct(bool);
+
+ #[derive(Copy, Clone, PartialEq, PartialOrd)]
+ enum Precedence {
+ Any,
+ Assign,
+ Range,
+ Or,
+ And,
+ Compare,
+ BitOr,
+ BitXor,
+ BitAnd,
+ Shift,
+ Arithmetic,
+ Term,
+ Cast,
+ }
+
+ impl Precedence {
+ fn of(op: &BinOp) -> Self {
+ match *op {
+ BinOp::Add(_) | BinOp::Sub(_) => Precedence::Arithmetic,
+ BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Term,
+ BinOp::And(_) => Precedence::And,
+ BinOp::Or(_) => Precedence::Or,
+ BinOp::BitXor(_) => Precedence::BitXor,
+ BinOp::BitAnd(_) => Precedence::BitAnd,
+ BinOp::BitOr(_) => Precedence::BitOr,
+ BinOp::Shl(_) | BinOp::Shr(_) => Precedence::Shift,
+ BinOp::Eq(_)
+ | BinOp::Lt(_)
+ | BinOp::Le(_)
+ | BinOp::Ne(_)
+ | BinOp::Ge(_)
+ | BinOp::Gt(_) => Precedence::Compare,
+ BinOp::AddEq(_)
+ | BinOp::SubEq(_)
+ | BinOp::MulEq(_)
+ | BinOp::DivEq(_)
+ | BinOp::RemEq(_)
+ | BinOp::BitXorEq(_)
+ | BinOp::BitAndEq(_)
+ | BinOp::BitOrEq(_)
+ | BinOp::ShlEq(_)
+ | BinOp::ShrEq(_) => Precedence::Assign,
+ }
+ }
+ }
+
+ impl Parse for Expr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ ambiguous_expr(input, AllowStruct(true))
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_no_struct(input: ParseStream) -> Result<Expr> {
+ ambiguous_expr(input, AllowStruct(false))
+ }
+
+ #[cfg(feature = "full")]
+ fn parse_expr(
+ input: ParseStream,
+ mut lhs: Expr,
+ allow_struct: AllowStruct,
+ base: Precedence,
+ ) -> Result<Expr> {
+ loop {
+ if input
+ .fork()
+ .parse::<BinOp>()
+ .ok()
+ .map_or(false, |op| Precedence::of(&op) >= base)
+ {
+ let op: BinOp = input.parse()?;
+ let precedence = Precedence::of(&op);
+ let mut rhs = unary_expr(input, allow_struct)?;
+ loop {
+ let next = peek_precedence(input);
+ if next > precedence || next == precedence && precedence == Precedence::Assign {
+ rhs = parse_expr(input, rhs, allow_struct, next)?;
+ } else {
+ break;
+ }
+ }
+ lhs = if precedence == Precedence::Assign {
+ Expr::AssignOp(ExprAssignOp {
+ attrs: Vec::new(),
+ left: Box::new(lhs),
+ op,
+ right: Box::new(rhs),
+ })
+ } else {
+ Expr::Binary(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(lhs),
+ op,
+ right: Box::new(rhs),
+ })
+ };
+ } else if Precedence::Assign >= base
+ && input.peek(Token![=])
+ && !input.peek(Token![==])
+ && !input.peek(Token![=>])
+ {
+ let eq_token: Token![=] = input.parse()?;
+ let mut rhs = unary_expr(input, allow_struct)?;
+ loop {
+ let next = peek_precedence(input);
+ if next >= Precedence::Assign {
+ rhs = parse_expr(input, rhs, allow_struct, next)?;
+ } else {
+ break;
+ }
+ }
+ lhs = Expr::Assign(ExprAssign {
+ attrs: Vec::new(),
+ left: Box::new(lhs),
+ eq_token,
+ right: Box::new(rhs),
+ });
+ } else if Precedence::Range >= base && input.peek(Token![..]) {
+ let limits: RangeLimits = input.parse()?;
+ let rhs = if input.is_empty()
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || !allow_struct.0 && input.peek(token::Brace)
+ {
+ None
+ } else {
+ let mut rhs = unary_expr(input, allow_struct)?;
+ loop {
+ let next = peek_precedence(input);
+ if next > Precedence::Range {
+ rhs = parse_expr(input, rhs, allow_struct, next)?;
+ } else {
+ break;
+ }
+ }
+ Some(rhs)
+ };
+ lhs = Expr::Range(ExprRange {
+ attrs: Vec::new(),
+ from: Some(Box::new(lhs)),
+ limits,
+ to: rhs.map(Box::new),
+ });
+ } else if Precedence::Cast >= base && input.peek(Token![as]) {
+ let as_token: Token![as] = input.parse()?;
+ let ty = input.call(Type::without_plus)?;
+ lhs = Expr::Cast(ExprCast {
+ attrs: Vec::new(),
+ expr: Box::new(lhs),
+ as_token,
+ ty: Box::new(ty),
+ });
+ } else if Precedence::Cast >= base && input.peek(Token![:]) && !input.peek(Token![::]) {
+ let colon_token: Token![:] = input.parse()?;
+ let ty = input.call(Type::without_plus)?;
+ lhs = Expr::Type(ExprType {
+ attrs: Vec::new(),
+ expr: Box::new(lhs),
+ colon_token,
+ ty: Box::new(ty),
+ });
+ } else {
+ break;
+ }
+ }
+ Ok(lhs)
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn parse_expr(
+ input: ParseStream,
+ mut lhs: Expr,
+ allow_struct: AllowStruct,
+ base: Precedence,
+ ) -> Result<Expr> {
+ loop {
+ if input
+ .fork()
+ .parse::<BinOp>()
+ .ok()
+ .map_or(false, |op| Precedence::of(&op) >= base)
+ {
+ let op: BinOp = input.parse()?;
+ let precedence = Precedence::of(&op);
+ let mut rhs = unary_expr(input, allow_struct)?;
+ loop {
+ let next = peek_precedence(input);
+ if next > precedence || next == precedence && precedence == Precedence::Assign {
+ rhs = parse_expr(input, rhs, allow_struct, next)?;
+ } else {
+ break;
+ }
+ }
+ lhs = Expr::Binary(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(lhs),
+ op,
+ right: Box::new(rhs),
+ });
+ } else if Precedence::Cast >= base && input.peek(Token![as]) {
+ let as_token: Token![as] = input.parse()?;
+ let ty = input.call(Type::without_plus)?;
+ lhs = Expr::Cast(ExprCast {
+ attrs: Vec::new(),
+ expr: Box::new(lhs),
+ as_token,
+ ty: Box::new(ty),
+ });
+ } else {
+ break;
+ }
+ }
+ Ok(lhs)
+ }
+
+ fn peek_precedence(input: ParseStream) -> Precedence {
+ if let Ok(op) = input.fork().parse() {
+ Precedence::of(&op)
+ } else if input.peek(Token![=]) && !input.peek(Token![=>]) {
+ Precedence::Assign
+ } else if input.peek(Token![..]) {
+ Precedence::Range
+ } else if input.peek(Token![as]) || input.peek(Token![:]) && !input.peek(Token![::]) {
+ Precedence::Cast
+ } else {
+ Precedence::Any
+ }
+ }
+
+ // Parse an arbitrary expression.
+ fn ambiguous_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let lhs = unary_expr(input, allow_struct)?;
+ parse_expr(input, lhs, allow_struct, Precedence::Any)
+ }
+
+ // <UnOp> <trailer>
+ // & <trailer>
+ // &mut <trailer>
+ // box <trailer>
+ #[cfg(feature = "full")]
+ fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let ahead = input.fork();
+ let attrs = ahead.call(Attribute::parse_outer)?;
+ if ahead.peek(Token![&])
+ || ahead.peek(Token![box])
+ || ahead.peek(Token![*])
+ || ahead.peek(Token![!])
+ || ahead.peek(Token![-])
+ {
+ input.advance_to(&ahead);
+ if input.peek(Token![&]) {
+ Ok(Expr::Reference(ExprReference {
+ attrs,
+ and_token: input.parse()?,
+ raw: Reserved::default(),
+ mutability: input.parse()?,
+ expr: Box::new(unary_expr(input, allow_struct)?),
+ }))
+ } else if input.peek(Token![box]) {
+ Ok(Expr::Box(ExprBox {
+ attrs,
+ box_token: input.parse()?,
+ expr: Box::new(unary_expr(input, allow_struct)?),
+ }))
+ } else {
+ Ok(Expr::Unary(ExprUnary {
+ attrs,
+ op: input.parse()?,
+ expr: Box::new(unary_expr(input, allow_struct)?),
+ }))
+ }
+ } else {
+ trailer_expr(input, allow_struct)
+ }
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let ahead = input.fork();
+ let attrs = ahead.call(Attribute::parse_outer)?;
+ if ahead.peek(Token![*]) || ahead.peek(Token![!]) || ahead.peek(Token![-]) {
+ input.advance_to(&ahead);
+ Ok(Expr::Unary(ExprUnary {
+ attrs,
+ op: input.parse()?,
+ expr: Box::new(unary_expr(input, allow_struct)?),
+ }))
+ } else {
+ trailer_expr(input, allow_struct)
+ }
+ }
+
+ // <atom> (..<args>) ...
+ // <atom> . <ident> (..<args>) ...
+ // <atom> . <ident> ...
+ // <atom> . <lit> ...
+ // <atom> [ <expr> ] ...
+ // <atom> ? ...
+ #[cfg(feature = "full")]
+ fn trailer_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ if input.peek(token::Group) {
+ return input.call(expr_group).map(Expr::Group);
+ }
+
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+
+ let atom = atom_expr(input, allow_struct)?;
+ let mut e = trailer_helper(input, atom)?;
+
+ let inner_attrs = e.replace_attrs(Vec::new());
+ let attrs = private::attrs(outer_attrs, inner_attrs);
+ e.replace_attrs(attrs);
+ Ok(e)
+ }
+
+ #[cfg(feature = "full")]
+ fn trailer_helper(input: ParseStream, mut e: Expr) -> Result<Expr> {
+ loop {
+ if input.peek(token::Paren) {
+ let content;
+ e = Expr::Call(ExprCall {
+ attrs: Vec::new(),
+ func: Box::new(e),
+ paren_token: parenthesized!(content in input),
+ args: content.parse_terminated(Expr::parse)?,
+ });
+ } else if input.peek(Token![.]) && !input.peek(Token![..]) {
+ let dot_token: Token![.] = input.parse()?;
+
+ if input.peek(token::Await) {
+ e = Expr::Await(ExprAwait {
+ attrs: Vec::new(),
+ base: Box::new(e),
+ dot_token,
+ await_token: input.parse()?,
+ });
+ continue;
+ }
+
+ let member: Member = input.parse()?;
+ let turbofish = if member.is_named() && input.peek(Token![::]) {
+ Some(MethodTurbofish {
+ colon2_token: input.parse()?,
+ lt_token: input.parse()?,
+ args: {
+ let mut args = Punctuated::new();
+ loop {
+ if input.peek(Token![>]) {
+ break;
+ }
+ let value = input.call(generic_method_argument)?;
+ args.push_value(value);
+ if input.peek(Token![>]) {
+ break;
+ }
+ let punct = input.parse()?;
+ args.push_punct(punct);
+ }
+ args
+ },
+ gt_token: input.parse()?,
+ })
+ } else {
+ None
+ };
+
+ if turbofish.is_some() || input.peek(token::Paren) {
+ if let Member::Named(method) = member {
+ let content;
+ e = Expr::MethodCall(ExprMethodCall {
+ attrs: Vec::new(),
+ receiver: Box::new(e),
+ dot_token,
+ method,
+ turbofish,
+ paren_token: parenthesized!(content in input),
+ args: content.parse_terminated(Expr::parse)?,
+ });
+ continue;
+ }
+ }
+
+ e = Expr::Field(ExprField {
+ attrs: Vec::new(),
+ base: Box::new(e),
+ dot_token,
+ member,
+ });
+ } else if input.peek(token::Bracket) {
+ let content;
+ e = Expr::Index(ExprIndex {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ bracket_token: bracketed!(content in input),
+ index: content.parse()?,
+ });
+ } else if input.peek(Token![?]) {
+ e = Expr::Try(ExprTry {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ question_token: input.parse()?,
+ });
+ } else {
+ break;
+ }
+ }
+ Ok(e)
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn trailer_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let mut e = atom_expr(input, allow_struct)?;
+
+ loop {
+ if input.peek(token::Paren) {
+ let content;
+ e = Expr::Call(ExprCall {
+ attrs: Vec::new(),
+ func: Box::new(e),
+ paren_token: parenthesized!(content in input),
+ args: content.parse_terminated(Expr::parse)?,
+ });
+ } else if input.peek(Token![.]) && !input.peek(Token![..]) && !input.peek2(token::Await)
+ {
+ e = Expr::Field(ExprField {
+ attrs: Vec::new(),
+ base: Box::new(e),
+ dot_token: input.parse()?,
+ member: input.parse()?,
+ });
+ } else if input.peek(token::Bracket) {
+ let content;
+ e = Expr::Index(ExprIndex {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ bracket_token: bracketed!(content in input),
+ index: content.parse()?,
+ });
+ } else {
+ break;
+ }
+ }
+
+ Ok(e)
+ }
+
+ // Parse all atomic expressions which don't have to worry about precedence
+ // interactions, as they are fully contained.
+ #[cfg(feature = "full")]
+ fn atom_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ if input.peek(token::Group) {
+ input.call(expr_group).map(Expr::Group)
+ } else if input.peek(Lit) {
+ input.parse().map(Expr::Lit)
+ } else if input.peek(Token![async])
+ && (input.peek2(token::Brace) || input.peek2(Token![move]) && input.peek3(token::Brace))
+ {
+ input.call(expr_async).map(Expr::Async)
+ } else if input.peek(Token![try]) && input.peek2(token::Brace) {
+ input.call(expr_try_block).map(Expr::TryBlock)
+ } else if input.peek(Token![|])
+ || input.peek(Token![async]) && (input.peek2(Token![|]) || input.peek2(Token![move]))
+ || input.peek(Token![static])
+ || input.peek(Token![move])
+ {
+ expr_closure(input, allow_struct).map(Expr::Closure)
+ } else if input.peek(Ident)
+ || input.peek(Token![::])
+ || input.peek(Token![<])
+ || input.peek(Token![self])
+ || input.peek(Token![Self])
+ || input.peek(Token![super])
+ || input.peek(Token![extern])
+ || input.peek(Token![crate])
+ {
+ path_or_macro_or_struct(input, allow_struct)
+ } else if input.peek(token::Paren) {
+ paren_or_tuple(input)
+ } else if input.peek(Token![break]) {
+ expr_break(input, allow_struct).map(Expr::Break)
+ } else if input.peek(Token![continue]) {
+ input.call(expr_continue).map(Expr::Continue)
+ } else if input.peek(Token![return]) {
+ expr_ret(input, allow_struct).map(Expr::Return)
+ } else if input.peek(token::Bracket) {
+ array_or_repeat(input)
+ } else if input.peek(Token![let]) {
+ input.call(expr_let).map(Expr::Let)
+ } else if input.peek(Token![if]) {
+ input.parse().map(Expr::If)
+ } else if input.peek(Token![while]) {
+ input.parse().map(Expr::While)
+ } else if input.peek(Token![for]) {
+ input.parse().map(Expr::ForLoop)
+ } else if input.peek(Token![loop]) {
+ input.parse().map(Expr::Loop)
+ } else if input.peek(Token![match]) {
+ input.parse().map(Expr::Match)
+ } else if input.peek(Token![yield]) {
+ input.call(expr_yield).map(Expr::Yield)
+ } else if input.peek(Token![unsafe]) {
+ input.call(expr_unsafe).map(Expr::Unsafe)
+ } else if input.peek(token::Brace) {
+ input.call(expr_block).map(Expr::Block)
+ } else if input.peek(Token![..]) {
+ expr_range(input, allow_struct).map(Expr::Range)
+ } else if input.peek(Lifetime) {
+ let the_label: Label = input.parse()?;
+ let mut expr = if input.peek(Token![while]) {
+ Expr::While(input.parse()?)
+ } else if input.peek(Token![for]) {
+ Expr::ForLoop(input.parse()?)
+ } else if input.peek(Token![loop]) {
+ Expr::Loop(input.parse()?)
+ } else if input.peek(token::Brace) {
+ Expr::Block(input.call(expr_block)?)
+ } else {
+ return Err(input.error("expected loop or block expression"));
+ };
+ match &mut expr {
+ Expr::While(ExprWhile { label, .. })
+ | Expr::ForLoop(ExprForLoop { label, .. })
+ | Expr::Loop(ExprLoop { label, .. })
+ | Expr::Block(ExprBlock { label, .. }) => *label = Some(the_label),
+ _ => unreachable!(),
+ }
+ Ok(expr)
+ } else {
+ Err(input.error("expected expression"))
+ }
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn atom_expr(input: ParseStream, _allow_struct: AllowStruct) -> Result<Expr> {
+ if input.peek(Lit) {
+ input.parse().map(Expr::Lit)
+ } else if input.peek(token::Paren) {
+ input.call(expr_paren).map(Expr::Paren)
+ } else if input.peek(Ident)
+ || input.peek(Token![::])
+ || input.peek(Token![<])
+ || input.peek(Token![self])
+ || input.peek(Token![Self])
+ || input.peek(Token![super])
+ || input.peek(Token![extern])
+ || input.peek(Token![crate])
+ {
+ input.parse().map(Expr::Path)
+ } else {
+ Err(input.error("unsupported expression; enable syn's features=[\"full\"]"))
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn path_or_macro_or_struct(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+ let expr: ExprPath = input.parse()?;
+ if expr.qself.is_some() {
+ return Ok(Expr::Path(expr));
+ }
+
+ if input.peek(Token![!]) && !input.peek(Token![!=]) {
+ let mut contains_arguments = false;
+ for segment in &expr.path.segments {
+ match segment.arguments {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => {
+ contains_arguments = true;
+ }
+ }
+ }
+
+ if !contains_arguments {
+ let bang_token: Token![!] = input.parse()?;
+ let (delimiter, tokens) = mac::parse_delimiter(input)?;
+ return Ok(Expr::Macro(ExprMacro {
+ attrs: Vec::new(),
+ mac: Macro {
+ path: expr.path,
+ bang_token,
+ delimiter,
+ tokens,
+ },
+ }));
+ }
+ }
+
+ if allow_struct.0 && input.peek(token::Brace) {
+ let outer_attrs = Vec::new();
+ expr_struct_helper(input, outer_attrs, expr.path).map(Expr::Struct)
+ } else {
+ Ok(Expr::Path(expr))
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn paren_or_tuple(input: ParseStream) -> Result<Expr> {
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ if content.is_empty() {
+ return Ok(Expr::Tuple(ExprTuple {
+ attrs: inner_attrs,
+ paren_token,
+ elems: Punctuated::new(),
+ }));
+ }
+
+ let first: Expr = content.parse()?;
+ if content.is_empty() {
+ return Ok(Expr::Paren(ExprParen {
+ attrs: inner_attrs,
+ paren_token,
+ expr: Box::new(first),
+ }));
+ }
+
+ let mut elems = Punctuated::new();
+ elems.push_value(first);
+ while !content.is_empty() {
+ let punct = content.parse()?;
+ elems.push_punct(punct);
+ if content.is_empty() {
+ break;
+ }
+ let value = content.parse()?;
+ elems.push_value(value);
+ }
+ Ok(Expr::Tuple(ExprTuple {
+ attrs: inner_attrs,
+ paren_token,
+ elems,
+ }))
+ }
+
+ #[cfg(feature = "full")]
+ fn array_or_repeat(input: ParseStream) -> Result<Expr> {
+ let content;
+ let bracket_token = bracketed!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ if content.is_empty() {
+ return Ok(Expr::Array(ExprArray {
+ attrs: inner_attrs,
+ bracket_token,
+ elems: Punctuated::new(),
+ }));
+ }
+
+ let first: Expr = content.parse()?;
+ if content.is_empty() || content.peek(Token![,]) {
+ let mut elems = Punctuated::new();
+ elems.push_value(first);
+ while !content.is_empty() {
+ let punct = content.parse()?;
+ elems.push_punct(punct);
+ if content.is_empty() {
+ break;
+ }
+ let value = content.parse()?;
+ elems.push_value(value);
+ }
+ Ok(Expr::Array(ExprArray {
+ attrs: inner_attrs,
+ bracket_token,
+ elems,
+ }))
+ } else if content.peek(Token![;]) {
+ let semi_token: Token![;] = content.parse()?;
+ let len: Expr = content.parse()?;
+ Ok(Expr::Repeat(ExprRepeat {
+ attrs: inner_attrs,
+ bracket_token,
+ expr: Box::new(first),
+ semi_token,
+ len: Box::new(len),
+ }))
+ } else {
+ Err(content.error("expected `,` or `;`"))
+ }
+ }
+
+ #[cfg(feature = "full")]
+ pub(crate) fn expr_early(input: ParseStream) -> Result<Expr> {
+ let mut attrs = input.call(Attribute::parse_outer)?;
+ let mut expr = if input.peek(Token![if]) {
+ Expr::If(input.parse()?)
+ } else if input.peek(Token![while]) {
+ Expr::While(input.parse()?)
+ } else if input.peek(Token![for]) {
+ Expr::ForLoop(input.parse()?)
+ } else if input.peek(Token![loop]) {
+ Expr::Loop(input.parse()?)
+ } else if input.peek(Token![match]) {
+ Expr::Match(input.parse()?)
+ } else if input.peek(Token![try]) && input.peek2(token::Brace) {
+ Expr::TryBlock(input.call(expr_try_block)?)
+ } else if input.peek(Token![unsafe]) {
+ Expr::Unsafe(input.call(expr_unsafe)?)
+ } else if input.peek(token::Brace) {
+ Expr::Block(input.call(expr_block)?)
+ } else {
+ let allow_struct = AllowStruct(true);
+ let mut expr = unary_expr(input, allow_struct)?;
+
+ attrs.extend(expr.replace_attrs(Vec::new()));
+ expr.replace_attrs(attrs);
+
+ return parse_expr(input, expr, allow_struct, Precedence::Any);
+ };
+
+ if input.peek(Token![.]) || input.peek(Token![?]) {
+ expr = trailer_helper(input, expr)?;
+
+ attrs.extend(expr.replace_attrs(Vec::new()));
+ expr.replace_attrs(attrs);
+
+ let allow_struct = AllowStruct(true);
+ return parse_expr(input, expr, allow_struct, Precedence::Any);
+ }
+
+ attrs.extend(expr.replace_attrs(Vec::new()));
+ expr.replace_attrs(attrs);
+ Ok(expr)
+ }
+
+ impl Parse for ExprLit {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ExprLit {
+ attrs: Vec::new(),
+ lit: input.parse()?,
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_group(input: ParseStream) -> Result<ExprGroup> {
+ let group = crate::group::parse_group(input)?;
+ Ok(ExprGroup {
+ attrs: Vec::new(),
+ group_token: group.token,
+ expr: group.content.parse()?,
+ })
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn expr_paren(input: ParseStream) -> Result<ExprParen> {
+ let content;
+ Ok(ExprParen {
+ attrs: Vec::new(),
+ paren_token: parenthesized!(content in input),
+ expr: content.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn generic_method_argument(input: ParseStream) -> Result<GenericMethodArgument> {
+ // TODO parse const generics as well
+ input.parse().map(GenericMethodArgument::Type)
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_let(input: ParseStream) -> Result<ExprLet> {
+ Ok(ExprLet {
+ attrs: Vec::new(),
+ let_token: input.parse()?,
+ pat: {
+ let leading_vert: Option<Token![|]> = input.parse()?;
+ let pat: Pat = input.parse()?;
+ if leading_vert.is_some()
+ || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
+ {
+ let mut cases = Punctuated::new();
+ cases.push_value(pat);
+ while input.peek(Token![|])
+ && !input.peek(Token![||])
+ && !input.peek(Token![|=])
+ {
+ let punct = input.parse()?;
+ cases.push_punct(punct);
+ let pat: Pat = input.parse()?;
+ cases.push_value(pat);
+ }
+ Pat::Or(PatOr {
+ attrs: Vec::new(),
+ leading_vert,
+ cases,
+ })
+ } else {
+ pat
+ }
+ },
+ eq_token: input.parse()?,
+ expr: Box::new(input.call(expr_no_struct)?),
+ })
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprIf {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ExprIf {
+ attrs: Vec::new(),
+ if_token: input.parse()?,
+ cond: Box::new(input.call(expr_no_struct)?),
+ then_branch: input.parse()?,
+ else_branch: {
+ if input.peek(Token![else]) {
+ Some(input.call(else_block)?)
+ } else {
+ None
+ }
+ },
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn else_block(input: ParseStream) -> Result<(Token![else], Box<Expr>)> {
+ let else_token: Token![else] = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ let else_branch = if input.peek(Token![if]) {
+ input.parse().map(Expr::If)?
+ } else if input.peek(token::Brace) {
+ Expr::Block(ExprBlock {
+ attrs: Vec::new(),
+ label: None,
+ block: input.parse()?,
+ })
+ } else {
+ return Err(lookahead.error());
+ };
+
+ Ok((else_token, Box::new(else_branch)))
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprForLoop {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let label: Option<Label> = input.parse()?;
+ let for_token: Token![for] = input.parse()?;
+
+ let leading_vert: Option<Token![|]> = input.parse()?;
+ let mut pat: Pat = input.parse()?;
+ if leading_vert.is_some() || input.peek(Token![|]) {
+ let mut cases = Punctuated::new();
+ cases.push_value(pat);
+ while input.peek(Token![|]) {
+ let punct = input.parse()?;
+ cases.push_punct(punct);
+ let pat: Pat = input.parse()?;
+ cases.push_value(pat);
+ }
+ pat = Pat::Or(PatOr {
+ attrs: Vec::new(),
+ leading_vert,
+ cases,
+ });
+ }
+
+ let in_token: Token![in] = input.parse()?;
+ let expr: Expr = input.call(expr_no_struct)?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprForLoop {
+ attrs: inner_attrs,
+ label,
+ for_token,
+ pat,
+ in_token,
+ expr: Box::new(expr),
+ body: Block { brace_token, stmts },
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprLoop {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let label: Option<Label> = input.parse()?;
+ let loop_token: Token![loop] = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprLoop {
+ attrs: inner_attrs,
+ label,
+ loop_token,
+ body: Block { brace_token, stmts },
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprMatch {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let match_token: Token![match] = input.parse()?;
+ let expr = expr_no_struct(input)?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+
+ let mut arms = Vec::new();
+ while !content.is_empty() {
+ arms.push(content.call(Arm::parse)?);
+ }
+
+ Ok(ExprMatch {
+ attrs: inner_attrs,
+ match_token,
+ expr: Box::new(expr),
+ brace_token,
+ arms,
+ })
+ }
+ }
+
+ macro_rules! impl_by_parsing_expr {
+ (
+ $(
+ $expr_type:ty, $variant:ident, $msg:expr,
+ )*
+ ) => {
+ $(
+ #[cfg(all(feature = "full", feature = "printing"))]
+ impl Parse for $expr_type {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut expr: Expr = input.parse()?;
+ loop {
+ match expr {
+ Expr::$variant(inner) => return Ok(inner),
+ Expr::Group(next) => expr = *next.expr,
+ _ => return Err(Error::new_spanned(expr, $msg)),
+ }
+ }
+ }
+ }
+ )*
+ };
+ }
+
+ impl_by_parsing_expr! {
+ ExprBox, Box, "expected box expression",
+ ExprArray, Array, "expected slice literal expression",
+ ExprCall, Call, "expected function call expression",
+ ExprMethodCall, MethodCall, "expected method call expression",
+ ExprTuple, Tuple, "expected tuple expression",
+ ExprBinary, Binary, "expected binary operation",
+ ExprUnary, Unary, "expected unary operation",
+ ExprCast, Cast, "expected cast expression",
+ ExprType, Type, "expected type ascription expression",
+ ExprLet, Let, "expected let guard",
+ ExprClosure, Closure, "expected closure expression",
+ ExprUnsafe, Unsafe, "expected unsafe block",
+ ExprBlock, Block, "expected blocked scope",
+ ExprAssign, Assign, "expected assignment expression",
+ ExprAssignOp, AssignOp, "expected compound assignment expression",
+ ExprField, Field, "expected struct field access",
+ ExprIndex, Index, "expected indexing expression",
+ ExprRange, Range, "expected range expression",
+ ExprReference, Reference, "expected referencing operation",
+ ExprBreak, Break, "expected break expression",
+ ExprContinue, Continue, "expected continue expression",
+ ExprReturn, Return, "expected return expression",
+ ExprMacro, Macro, "expected macro invocation expression",
+ ExprStruct, Struct, "expected struct literal expression",
+ ExprRepeat, Repeat, "expected array literal constructed from one repeated element",
+ ExprParen, Paren, "expected parenthesized expression",
+ ExprTry, Try, "expected try expression",
+ ExprAsync, Async, "expected async block",
+ ExprTryBlock, TryBlock, "expected try block",
+ ExprYield, Yield, "expected yield expression",
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_try_block(input: ParseStream) -> Result<ExprTryBlock> {
+ Ok(ExprTryBlock {
+ attrs: Vec::new(),
+ try_token: input.parse()?,
+ block: input.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_yield(input: ParseStream) -> Result<ExprYield> {
+ Ok(ExprYield {
+ attrs: Vec::new(),
+ yield_token: input.parse()?,
+ expr: {
+ if !input.is_empty() && !input.peek(Token![,]) && !input.peek(Token![;]) {
+ Some(input.parse()?)
+ } else {
+ None
+ }
+ },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_closure(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprClosure> {
+ let asyncness: Option<Token![async]> = input.parse()?;
+ let movability: Option<Token![static]> = if asyncness.is_none() {
+ input.parse()?
+ } else {
+ None
+ };
+ let capture: Option<Token![move]> = input.parse()?;
+ let or1_token: Token![|] = input.parse()?;
+
+ let mut inputs = Punctuated::new();
+ loop {
+ if input.peek(Token![|]) {
+ break;
+ }
+ let value = closure_arg(input)?;
+ inputs.push_value(value);
+ if input.peek(Token![|]) {
+ break;
+ }
+ let punct: Token![,] = input.parse()?;
+ inputs.push_punct(punct);
+ }
+
+ let or2_token: Token![|] = input.parse()?;
+
+ let (output, body) = if input.peek(Token![->]) {
+ let arrow_token: Token![->] = input.parse()?;
+ let ty: Type = input.parse()?;
+ let body: Block = input.parse()?;
+ let output = ReturnType::Type(arrow_token, Box::new(ty));
+ let block = Expr::Block(ExprBlock {
+ attrs: Vec::new(),
+ label: None,
+ block: body,
+ });
+ (output, block)
+ } else {
+ let body = ambiguous_expr(input, allow_struct)?;
+ (ReturnType::Default, body)
+ };
+
+ Ok(ExprClosure {
+ attrs: Vec::new(),
+ asyncness,
+ movability,
+ capture,
+ or1_token,
+ inputs,
+ or2_token,
+ output,
+ body: Box::new(body),
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_async(input: ParseStream) -> Result<ExprAsync> {
+ Ok(ExprAsync {
+ attrs: Vec::new(),
+ async_token: input.parse()?,
+ capture: input.parse()?,
+ block: input.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn closure_arg(input: ParseStream) -> Result<Pat> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let mut pat: Pat = input.parse()?;
+
+ if input.peek(Token![:]) {
+ Ok(Pat::Type(PatType {
+ attrs,
+ pat: Box::new(pat),
+ colon_token: input.parse()?,
+ ty: input.parse()?,
+ }))
+ } else {
+ match &mut pat {
+ Pat::Box(pat) => pat.attrs = attrs,
+ Pat::Ident(pat) => pat.attrs = attrs,
+ Pat::Lit(pat) => pat.attrs = attrs,
+ Pat::Macro(pat) => pat.attrs = attrs,
+ Pat::Or(pat) => pat.attrs = attrs,
+ Pat::Path(pat) => pat.attrs = attrs,
+ Pat::Range(pat) => pat.attrs = attrs,
+ Pat::Reference(pat) => pat.attrs = attrs,
+ Pat::Rest(pat) => pat.attrs = attrs,
+ Pat::Slice(pat) => pat.attrs = attrs,
+ Pat::Struct(pat) => pat.attrs = attrs,
+ Pat::Tuple(pat) => pat.attrs = attrs,
+ Pat::TupleStruct(pat) => pat.attrs = attrs,
+ Pat::Type(_) => unreachable!(),
+ Pat::Verbatim(_) => {}
+ Pat::Wild(pat) => pat.attrs = attrs,
+ Pat::__Nonexhaustive => unreachable!(),
+ }
+ Ok(pat)
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for ExprWhile {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let label: Option<Label> = input.parse()?;
+ let while_token: Token![while] = input.parse()?;
+ let cond = expr_no_struct(input)?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprWhile {
+ attrs: inner_attrs,
+ label,
+ while_token,
+ cond: Box::new(cond),
+ body: Block { brace_token, stmts },
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for Label {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Label {
+ name: input.parse()?,
+ colon_token: input.parse()?,
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for Option<Label> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Lifetime) {
+ input.parse().map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_continue(input: ParseStream) -> Result<ExprContinue> {
+ Ok(ExprContinue {
+ attrs: Vec::new(),
+ continue_token: input.parse()?,
+ label: input.parse()?,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_break(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprBreak> {
+ Ok(ExprBreak {
+ attrs: Vec::new(),
+ break_token: input.parse()?,
+ label: input.parse()?,
+ expr: {
+ if input.is_empty()
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || !allow_struct.0 && input.peek(token::Brace)
+ {
+ None
+ } else {
+ let expr = ambiguous_expr(input, allow_struct)?;
+ Some(Box::new(expr))
+ }
+ },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_ret(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprReturn> {
+ Ok(ExprReturn {
+ attrs: Vec::new(),
+ return_token: input.parse()?,
+ expr: {
+ if input.is_empty() || input.peek(Token![,]) || input.peek(Token![;]) {
+ None
+ } else {
+ // NOTE: return is greedy and eats blocks after it even when in a
+ // position where structs are not allowed, such as in if statement
+ // conditions. For example:
+ //
+ // if return { println!("A") } {} // Prints "A"
+ let expr = ambiguous_expr(input, allow_struct)?;
+ Some(Box::new(expr))
+ }
+ },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for FieldValue {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let member: Member = input.parse()?;
+ let (colon_token, value) = if input.peek(Token![:]) || !member.is_named() {
+ let colon_token: Token![:] = input.parse()?;
+ let value: Expr = input.parse()?;
+ (Some(colon_token), value)
+ } else if let Member::Named(ident) = &member {
+ let value = Expr::Path(ExprPath {
+ attrs: Vec::new(),
+ qself: None,
+ path: Path::from(ident.clone()),
+ });
+ (None, value)
+ } else {
+ unreachable!()
+ };
+
+ Ok(FieldValue {
+ attrs,
+ member,
+ colon_token,
+ expr: value,
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_struct_helper(
+ input: ParseStream,
+ outer_attrs: Vec<Attribute>,
+ path: Path,
+ ) -> Result<ExprStruct> {
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let attrs = private::attrs(outer_attrs, inner_attrs);
+
+ let mut fields = Punctuated::new();
+ while !content.is_empty() {
+ if content.peek(Token![..]) {
+ return Ok(ExprStruct {
+ attrs,
+ brace_token,
+ path,
+ fields,
+ dot2_token: Some(content.parse()?),
+ rest: Some(Box::new(content.parse()?)),
+ });
+ }
+
+ fields.push(content.parse()?);
+ if !content.peek(Token![,]) {
+ break;
+ }
+ let punct: Token![,] = content.parse()?;
+ fields.push_punct(punct);
+ }
+
+ Ok(ExprStruct {
+ attrs,
+ brace_token,
+ path,
+ fields,
+ dot2_token: None,
+ rest: None,
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_unsafe(input: ParseStream) -> Result<ExprUnsafe> {
+ let unsafe_token: Token![unsafe] = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprUnsafe {
+ attrs: inner_attrs,
+ unsafe_token,
+ block: Block { brace_token, stmts },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ pub fn expr_block(input: ParseStream) -> Result<ExprBlock> {
+ let label: Option<Label> = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ExprBlock {
+ attrs: inner_attrs,
+ label,
+ block: Block { brace_token, stmts },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ fn expr_range(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprRange> {
+ Ok(ExprRange {
+ attrs: Vec::new(),
+ from: None,
+ limits: input.parse()?,
+ to: {
+ if input.is_empty()
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || !allow_struct.0 && input.peek(token::Brace)
+ {
+ None
+ } else {
+ let to = ambiguous_expr(input, allow_struct)?;
+ Some(Box::new(to))
+ }
+ },
+ })
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for RangeLimits {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![..=]) {
+ input.parse().map(RangeLimits::Closed)
+ } else if lookahead.peek(Token![...]) {
+ let dot3: Token![...] = input.parse()?;
+ Ok(RangeLimits::Closed(Token![..=](dot3.spans)))
+ } else if lookahead.peek(Token![..]) {
+ input.parse().map(RangeLimits::HalfOpen)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ impl Parse for ExprPath {
+ fn parse(input: ParseStream) -> Result<Self> {
+ #[cfg(not(feature = "full"))]
+ let attrs = Vec::new();
+ #[cfg(feature = "full")]
+ let attrs = input.call(Attribute::parse_outer)?;
+
+ let (qself, path) = path::parsing::qpath(input, true)?;
+
+ Ok(ExprPath { attrs, qself, path })
+ }
+ }
+
+ impl Parse for Member {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Ident) {
+ input.parse().map(Member::Named)
+ } else if input.peek(LitInt) {
+ input.parse().map(Member::Unnamed)
+ } else {
+ Err(input.error("expected identifier or integer"))
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for Arm {
+ fn parse(input: ParseStream) -> Result<Arm> {
+ let requires_comma;
+ Ok(Arm {
+ attrs: input.call(Attribute::parse_outer)?,
+ pat: {
+ let leading_vert: Option<Token![|]> = input.parse()?;
+ let pat: Pat = input.parse()?;
+ if leading_vert.is_some() || input.peek(Token![|]) {
+ let mut cases = Punctuated::new();
+ cases.push_value(pat);
+ while input.peek(Token![|]) {
+ let punct = input.parse()?;
+ cases.push_punct(punct);
+ let pat: Pat = input.parse()?;
+ cases.push_value(pat);
+ }
+ Pat::Or(PatOr {
+ attrs: Vec::new(),
+ leading_vert,
+ cases,
+ })
+ } else {
+ pat
+ }
+ },
+ guard: {
+ if input.peek(Token![if]) {
+ let if_token: Token![if] = input.parse()?;
+ let guard: Expr = input.parse()?;
+ Some((if_token, Box::new(guard)))
+ } else {
+ None
+ }
+ },
+ fat_arrow_token: input.parse()?,
+ body: {
+ let body = input.call(expr_early)?;
+ requires_comma = requires_terminator(&body);
+ Box::new(body)
+ },
+ comma: {
+ if requires_comma && !input.is_empty() {
+ Some(input.parse()?)
+ } else {
+ input.parse()?
+ }
+ },
+ })
+ }
+ }
+
+ impl Parse for Index {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lit: LitInt = input.parse()?;
+ if lit.suffix().is_empty() {
+ Ok(Index {
+ index: lit
+ .base10_digits()
+ .parse()
+ .map_err(|err| Error::new(lit.span(), err))?,
+ span: lit.span(),
+ })
+ } else {
+ Err(Error::new(lit.span(), "expected unsuffixed integer"))
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Member {
+ fn is_named(&self) -> bool {
+ match *self {
+ Member::Named(_) => true,
+ Member::Unnamed(_) => false,
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+pub(crate) mod printing {
+ use super::*;
+
+ use proc_macro2::{Literal, TokenStream};
+ use quote::{ToTokens, TokenStreamExt};
+
+ #[cfg(feature = "full")]
+ use crate::attr::FilterAttrs;
+ #[cfg(feature = "full")]
+ use crate::print::TokensOrDefault;
+
+ // If the given expression is a bare `ExprStruct`, wraps it in parenthesis
+ // before appending it to `TokenStream`.
+ #[cfg(feature = "full")]
+ fn wrap_bare_struct(tokens: &mut TokenStream, e: &Expr) {
+ if let Expr::Struct(_) = *e {
+ token::Paren::default().surround(tokens, |tokens| {
+ e.to_tokens(tokens);
+ });
+ } else {
+ e.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ pub(crate) fn outer_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) {
+ tokens.append_all(attrs.outer());
+ }
+
+ #[cfg(feature = "full")]
+ fn inner_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) {
+ tokens.append_all(attrs.inner());
+ }
+
+ #[cfg(not(feature = "full"))]
+ pub(crate) fn outer_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {}
+
+ #[cfg(not(feature = "full"))]
+ fn inner_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {}
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBox {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.box_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprArray {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.elems.to_tokens(tokens);
+ })
+ }
+ }
+
+ impl ToTokens for ExprCall {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.func.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.args.to_tokens(tokens);
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMethodCall {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.receiver.to_tokens(tokens);
+ self.dot_token.to_tokens(tokens);
+ self.method.to_tokens(tokens);
+ self.turbofish.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.args.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for MethodTurbofish {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.colon2_token.to_tokens(tokens);
+ self.lt_token.to_tokens(tokens);
+ self.args.to_tokens(tokens);
+ self.gt_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for GenericMethodArgument {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ GenericMethodArgument::Type(t) => t.to_tokens(tokens),
+ GenericMethodArgument::Const(c) => c.to_tokens(tokens),
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.elems.to_tokens(tokens);
+ // If we only have one argument, we need a trailing comma to
+ // distinguish ExprTuple from ExprParen.
+ if self.elems.len() == 1 && !self.elems.trailing_punct() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ })
+ }
+ }
+
+ impl ToTokens for ExprBinary {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.op.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprUnary {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.op.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprLit {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.lit.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprCast {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.as_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn maybe_wrap_else(tokens: &mut TokenStream, else_: &Option<(Token![else], Box<Expr>)>) {
+ if let Some((else_token, else_)) = else_ {
+ else_token.to_tokens(tokens);
+
+ // If we are not one of the valid expressions to exist in an else
+ // clause, wrap ourselves in a block.
+ match **else_ {
+ Expr::If(_) | Expr::Block(_) => {
+ else_.to_tokens(tokens);
+ }
+ _ => {
+ token::Brace::default().surround(tokens, |tokens| {
+ else_.to_tokens(tokens);
+ });
+ }
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprLet {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.let_token.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprIf {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.if_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.cond);
+ self.then_branch.to_tokens(tokens);
+ maybe_wrap_else(tokens, &self.else_branch);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprWhile {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.while_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.cond);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprForLoop {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.for_token.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ self.in_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprLoop {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.loop_token.to_tokens(tokens);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMatch {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.match_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ self.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ for (i, arm) in self.arms.iter().enumerate() {
+ arm.to_tokens(tokens);
+ // Ensure that we have a comma after a non-block arm, except
+ // for the last one.
+ let is_last = i == self.arms.len() - 1;
+ if !is_last && requires_terminator(&arm.body) && arm.comma.is_none() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ }
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAsync {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.async_token.to_tokens(tokens);
+ self.capture.to_tokens(tokens);
+ self.block.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAwait {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.base.to_tokens(tokens);
+ self.dot_token.to_tokens(tokens);
+ self.await_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTryBlock {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.try_token.to_tokens(tokens);
+ self.block.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprYield {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.yield_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprClosure {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.asyncness.to_tokens(tokens);
+ self.movability.to_tokens(tokens);
+ self.capture.to_tokens(tokens);
+ self.or1_token.to_tokens(tokens);
+ self.inputs.to_tokens(tokens);
+ self.or2_token.to_tokens(tokens);
+ self.output.to_tokens(tokens);
+ self.body.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprUnsafe {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.unsafe_token.to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBlock {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAssign {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAssignOp {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.op.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprField {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.base.to_tokens(tokens);
+ self.dot_token.to_tokens(tokens);
+ self.member.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Member {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ Member::Named(ident) => ident.to_tokens(tokens),
+ Member::Unnamed(index) => index.to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for Index {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let mut lit = Literal::i64_unsuffixed(i64::from(self.index));
+ lit.set_span(self.span);
+ tokens.append(lit);
+ }
+ }
+
+ impl ToTokens for ExprIndex {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ self.index.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprRange {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.from.to_tokens(tokens);
+ match &self.limits {
+ RangeLimits::HalfOpen(t) => t.to_tokens(tokens),
+ RangeLimits::Closed(t) => t.to_tokens(tokens),
+ }
+ self.to.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprPath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ private::print_path(tokens, &self.qself, &self.path);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprReference {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.and_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBreak {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.break_token.to_tokens(tokens);
+ self.label.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprContinue {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.continue_token.to_tokens(tokens);
+ self.label.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprReturn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.return_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.mac.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.path.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.fields.to_tokens(tokens);
+ if self.rest.is_some() {
+ TokensOrDefault(&self.dot2_token).to_tokens(tokens);
+ self.rest.to_tokens(tokens);
+ }
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprRepeat {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ self.len.to_tokens(tokens);
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprGroup {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.group_token.surround(tokens, |tokens| {
+ self.expr.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for ExprParen {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTry {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.question_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Label {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.name.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for FieldValue {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.member.to_tokens(tokens);
+ if let Some(colon_token) = &self.colon_token {
+ colon_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Arm {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.pat.to_tokens(tokens);
+ if let Some((if_token, guard)) = &self.guard {
+ if_token.to_tokens(tokens);
+ guard.to_tokens(tokens);
+ }
+ self.fat_arrow_token.to_tokens(tokens);
+ self.body.to_tokens(tokens);
+ self.comma.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn/src/ext.rs b/syn/src/ext.rs
new file mode 100644
index 0000000..d09577a
--- /dev/null
+++ b/syn/src/ext.rs
@@ -0,0 +1,135 @@
+//! Extension traits to provide parsing methods on foreign types.
+//!
+//! *This module is available if Syn is built with the `"parsing"` feature.*
+
+use proc_macro2::Ident;
+
+use crate::parse::{ParseStream, Result};
+
+use crate::buffer::Cursor;
+use crate::parse::Peek;
+use crate::sealed::lookahead;
+use crate::token::CustomToken;
+
+/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro.
+///
+/// This trait is sealed and cannot be implemented for types outside of Syn. It
+/// is implemented only for `proc_macro2::Ident`.
+///
+/// *This trait is available if Syn is built with the `"parsing"` feature.*
+pub trait IdentExt: Sized + private::Sealed {
+ /// Parses any identifier including keywords.
+ ///
+ /// This is useful when parsing macro input which allows Rust keywords as
+ /// identifiers.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{Error, Ident, Result, Token};
+ /// use syn::ext::IdentExt;
+ /// use syn::parse::ParseStream;
+ ///
+ /// mod kw {
+ /// syn::custom_keyword!(name);
+ /// }
+ ///
+ /// // Parses input that looks like `name = NAME` where `NAME` can be
+ /// // any identifier.
+ /// //
+ /// // Examples:
+ /// //
+ /// // name = anything
+ /// // name = impl
+ /// fn parse_dsl(input: ParseStream) -> Result<Ident> {
+ /// input.parse::<kw::name>()?;
+ /// input.parse::<Token![=]>()?;
+ /// let name = input.call(Ident::parse_any)?;
+ /// Ok(name)
+ /// }
+ /// ```
+ fn parse_any(input: ParseStream) -> Result<Self>;
+
+ /// Peeks any identifier including keywords. Usage:
+ /// `input.peek(Ident::peek_any)`
+ ///
+ /// This is different from `input.peek(Ident)` which only returns true in
+ /// the case of an ident which is not a Rust keyword.
+ #[allow(non_upper_case_globals)]
+ const peek_any: private::PeekFn = private::PeekFn;
+
+ /// Strips the raw marker `r#`, if any, from the beginning of an ident.
+ ///
+ /// - unraw(`x`) = `x`
+ /// - unraw(`move`) = `move`
+ /// - unraw(`r#move`) = `move`
+ ///
+ /// # Example
+ ///
+ /// In the case of interop with other languages like Python that have a
+ /// different set of keywords than Rust, we might come across macro input
+ /// that involves raw identifiers to refer to ordinary variables in the
+ /// other language with a name that happens to be a Rust keyword.
+ ///
+ /// The function below appends an identifier from the caller's input onto a
+ /// fixed prefix. Without using `unraw()`, this would tend to produce
+ /// invalid identifiers like `__pyo3_get_r#move`.
+ ///
+ /// ```
+ /// use proc_macro2::Span;
+ /// use syn::Ident;
+ /// use syn::ext::IdentExt;
+ ///
+ /// fn ident_for_getter(variable: &Ident) -> Ident {
+ /// let getter = format!("__pyo3_get_{}", variable.unraw());
+ /// Ident::new(&getter, Span::call_site())
+ /// }
+ /// ```
+ fn unraw(&self) -> Ident;
+}
+
+impl IdentExt for Ident {
+ fn parse_any(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| match cursor.ident() {
+ Some((ident, rest)) => Ok((ident, rest)),
+ None => Err(cursor.error("expected ident")),
+ })
+ }
+
+ fn unraw(&self) -> Ident {
+ let string = self.to_string();
+ if string.starts_with("r#") {
+ Ident::new(&string[2..], self.span())
+ } else {
+ self.clone()
+ }
+ }
+}
+
+impl Peek for private::PeekFn {
+ type Token = private::IdentAny;
+}
+
+impl CustomToken for private::IdentAny {
+ fn peek(cursor: Cursor) -> bool {
+ cursor.ident().is_some()
+ }
+
+ fn display() -> &'static str {
+ "identifier"
+ }
+}
+
+impl lookahead::Sealed for private::PeekFn {}
+
+mod private {
+ use proc_macro2::Ident;
+
+ pub trait Sealed {}
+
+ impl Sealed for Ident {}
+
+ #[derive(Copy, Clone)]
+ pub struct PeekFn;
+ pub struct IdentAny;
+}
diff --git a/syn/src/file.rs b/syn/src/file.rs
new file mode 100644
index 0000000..88c02fe
--- /dev/null
+++ b/syn/src/file.rs
@@ -0,0 +1,113 @@
+use super::*;
+
+ast_struct! {
+ /// A complete file of Rust source code.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Example
+ ///
+ /// Parse a Rust source file into a `syn::File` and print out a debug
+ /// representation of the syntax tree.
+ ///
+ /// ```
+ /// use std::env;
+ /// use std::fs::File;
+ /// use std::io::Read;
+ /// use std::process;
+ ///
+ /// fn main() {
+ /// # }
+ /// #
+ /// # fn fake_main() {
+ /// let mut args = env::args();
+ /// let _ = args.next(); // executable name
+ ///
+ /// let filename = match (args.next(), args.next()) {
+ /// (Some(filename), None) => filename,
+ /// _ => {
+ /// eprintln!("Usage: dump-syntax path/to/filename.rs");
+ /// process::exit(1);
+ /// }
+ /// };
+ ///
+ /// let mut file = File::open(&filename).expect("Unable to open file");
+ ///
+ /// let mut src = String::new();
+ /// file.read_to_string(&mut src).expect("Unable to read file");
+ ///
+ /// let syntax = syn::parse_file(&src).expect("Unable to parse file");
+ /// println!("{:#?}", syntax);
+ /// }
+ /// ```
+ ///
+ /// Running with its own source code as input, this program prints output
+ /// that begins with:
+ ///
+ /// ```text
+ /// File {
+ /// shebang: None,
+ /// attrs: [],
+ /// items: [
+ /// ExternCrate(
+ /// ItemExternCrate {
+ /// attrs: [],
+ /// vis: Inherited,
+ /// extern_token: Extern,
+ /// crate_token: Crate,
+ /// ident: Ident {
+ /// term: Term(
+ /// "syn"
+ /// ),
+ /// span: Span
+ /// },
+ /// rename: None,
+ /// semi_token: Semi
+ /// }
+ /// ),
+ /// ...
+ /// ```
+ pub struct File {
+ pub shebang: Option<String>,
+ pub attrs: Vec<Attribute>,
+ pub items: Vec<Item>,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::parse::{Parse, ParseStream, Result};
+
+ impl Parse for File {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(File {
+ shebang: None,
+ attrs: input.call(Attribute::parse_inner)?,
+ items: {
+ let mut items = Vec::new();
+ while !input.is_empty() {
+ items.push(input.parse()?);
+ }
+ items
+ },
+ })
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use crate::attr::FilterAttrs;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for File {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.items);
+ }
+ }
+}
diff --git a/syn/src/gen/fold.rs b/syn/src/gen/fold.rs
new file mode 100644
index 0000000..f51218b
--- /dev/null
+++ b/syn/src/gen/fold.rs
@@ -0,0 +1,3236 @@
+// This file is @generated by syn-internal-codegen.
+// It is not intended for manual editing.
+
+#![allow(unreachable_code, unused_variables)]
+#[cfg(any(feature = "full", feature = "derive"))]
+use crate::gen::helper::fold::*;
+#[cfg(any(feature = "full", feature = "derive"))]
+use crate::token::{Brace, Bracket, Group, Paren};
+use crate::*;
+use proc_macro2::Span;
+#[cfg(feature = "full")]
+macro_rules! full {
+ ($e:expr) => {
+ $e
+ };
+}
+#[cfg(all(feature = "derive", not(feature = "full")))]
+macro_rules! full {
+ ($e:expr) => {
+ unreachable!()
+ };
+}
+/// Syntax tree traversal to transform the nodes of an owned syntax tree.
+///
+/// See the [module documentation] for details.
+///
+/// [module documentation]: self
+///
+/// *This trait is available if Syn is built with the `"fold"` feature.*
+pub trait Fold {
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_abi(&mut self, i: Abi) -> Abi {
+ fold_abi(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_angle_bracketed_generic_arguments(
+ &mut self,
+ i: AngleBracketedGenericArguments,
+ ) -> AngleBracketedGenericArguments {
+ fold_angle_bracketed_generic_arguments(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_arm(&mut self, i: Arm) -> Arm {
+ fold_arm(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_attr_style(&mut self, i: AttrStyle) -> AttrStyle {
+ fold_attr_style(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_attribute(&mut self, i: Attribute) -> Attribute {
+ fold_attribute(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_bare_fn_arg(&mut self, i: BareFnArg) -> BareFnArg {
+ fold_bare_fn_arg(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_bin_op(&mut self, i: BinOp) -> BinOp {
+ fold_bin_op(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_binding(&mut self, i: Binding) -> Binding {
+ fold_binding(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_block(&mut self, i: Block) -> Block {
+ fold_block(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_bound_lifetimes(&mut self, i: BoundLifetimes) -> BoundLifetimes {
+ fold_bound_lifetimes(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_const_param(&mut self, i: ConstParam) -> ConstParam {
+ fold_const_param(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_constraint(&mut self, i: Constraint) -> Constraint {
+ fold_constraint(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_data(&mut self, i: Data) -> Data {
+ fold_data(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_data_enum(&mut self, i: DataEnum) -> DataEnum {
+ fold_data_enum(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_data_struct(&mut self, i: DataStruct) -> DataStruct {
+ fold_data_struct(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_data_union(&mut self, i: DataUnion) -> DataUnion {
+ fold_data_union(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_derive_input(&mut self, i: DeriveInput) -> DeriveInput {
+ fold_derive_input(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr(&mut self, i: Expr) -> Expr {
+ fold_expr(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_array(&mut self, i: ExprArray) -> ExprArray {
+ fold_expr_array(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_assign(&mut self, i: ExprAssign) -> ExprAssign {
+ fold_expr_assign(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_assign_op(&mut self, i: ExprAssignOp) -> ExprAssignOp {
+ fold_expr_assign_op(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_async(&mut self, i: ExprAsync) -> ExprAsync {
+ fold_expr_async(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_await(&mut self, i: ExprAwait) -> ExprAwait {
+ fold_expr_await(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_binary(&mut self, i: ExprBinary) -> ExprBinary {
+ fold_expr_binary(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_block(&mut self, i: ExprBlock) -> ExprBlock {
+ fold_expr_block(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_box(&mut self, i: ExprBox) -> ExprBox {
+ fold_expr_box(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_break(&mut self, i: ExprBreak) -> ExprBreak {
+ fold_expr_break(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_call(&mut self, i: ExprCall) -> ExprCall {
+ fold_expr_call(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_cast(&mut self, i: ExprCast) -> ExprCast {
+ fold_expr_cast(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_closure(&mut self, i: ExprClosure) -> ExprClosure {
+ fold_expr_closure(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_continue(&mut self, i: ExprContinue) -> ExprContinue {
+ fold_expr_continue(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_field(&mut self, i: ExprField) -> ExprField {
+ fold_expr_field(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_for_loop(&mut self, i: ExprForLoop) -> ExprForLoop {
+ fold_expr_for_loop(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_group(&mut self, i: ExprGroup) -> ExprGroup {
+ fold_expr_group(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_if(&mut self, i: ExprIf) -> ExprIf {
+ fold_expr_if(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_index(&mut self, i: ExprIndex) -> ExprIndex {
+ fold_expr_index(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_let(&mut self, i: ExprLet) -> ExprLet {
+ fold_expr_let(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_lit(&mut self, i: ExprLit) -> ExprLit {
+ fold_expr_lit(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_loop(&mut self, i: ExprLoop) -> ExprLoop {
+ fold_expr_loop(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_macro(&mut self, i: ExprMacro) -> ExprMacro {
+ fold_expr_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_match(&mut self, i: ExprMatch) -> ExprMatch {
+ fold_expr_match(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_method_call(&mut self, i: ExprMethodCall) -> ExprMethodCall {
+ fold_expr_method_call(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_paren(&mut self, i: ExprParen) -> ExprParen {
+ fold_expr_paren(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_path(&mut self, i: ExprPath) -> ExprPath {
+ fold_expr_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_range(&mut self, i: ExprRange) -> ExprRange {
+ fold_expr_range(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_reference(&mut self, i: ExprReference) -> ExprReference {
+ fold_expr_reference(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_repeat(&mut self, i: ExprRepeat) -> ExprRepeat {
+ fold_expr_repeat(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_return(&mut self, i: ExprReturn) -> ExprReturn {
+ fold_expr_return(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_struct(&mut self, i: ExprStruct) -> ExprStruct {
+ fold_expr_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_try(&mut self, i: ExprTry) -> ExprTry {
+ fold_expr_try(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_try_block(&mut self, i: ExprTryBlock) -> ExprTryBlock {
+ fold_expr_try_block(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_tuple(&mut self, i: ExprTuple) -> ExprTuple {
+ fold_expr_tuple(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_type(&mut self, i: ExprType) -> ExprType {
+ fold_expr_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_expr_unary(&mut self, i: ExprUnary) -> ExprUnary {
+ fold_expr_unary(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_unsafe(&mut self, i: ExprUnsafe) -> ExprUnsafe {
+ fold_expr_unsafe(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_while(&mut self, i: ExprWhile) -> ExprWhile {
+ fold_expr_while(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_expr_yield(&mut self, i: ExprYield) -> ExprYield {
+ fold_expr_yield(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_field(&mut self, i: Field) -> Field {
+ fold_field(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_field_pat(&mut self, i: FieldPat) -> FieldPat {
+ fold_field_pat(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_field_value(&mut self, i: FieldValue) -> FieldValue {
+ fold_field_value(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_fields(&mut self, i: Fields) -> Fields {
+ fold_fields(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_fields_named(&mut self, i: FieldsNamed) -> FieldsNamed {
+ fold_fields_named(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_fields_unnamed(&mut self, i: FieldsUnnamed) -> FieldsUnnamed {
+ fold_fields_unnamed(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_file(&mut self, i: File) -> File {
+ fold_file(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_fn_arg(&mut self, i: FnArg) -> FnArg {
+ fold_fn_arg(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item(&mut self, i: ForeignItem) -> ForeignItem {
+ fold_foreign_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_fn(&mut self, i: ForeignItemFn) -> ForeignItemFn {
+ fold_foreign_item_fn(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_macro(&mut self, i: ForeignItemMacro) -> ForeignItemMacro {
+ fold_foreign_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_static(&mut self, i: ForeignItemStatic) -> ForeignItemStatic {
+ fold_foreign_item_static(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_type(&mut self, i: ForeignItemType) -> ForeignItemType {
+ fold_foreign_item_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_generic_argument(&mut self, i: GenericArgument) -> GenericArgument {
+ fold_generic_argument(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_generic_method_argument(&mut self, i: GenericMethodArgument) -> GenericMethodArgument {
+ fold_generic_method_argument(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_generic_param(&mut self, i: GenericParam) -> GenericParam {
+ fold_generic_param(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_generics(&mut self, i: Generics) -> Generics {
+ fold_generics(self, i)
+ }
+ fn fold_ident(&mut self, i: Ident) -> Ident {
+ fold_ident(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem {
+ fold_impl_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_const(&mut self, i: ImplItemConst) -> ImplItemConst {
+ fold_impl_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_macro(&mut self, i: ImplItemMacro) -> ImplItemMacro {
+ fold_impl_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_method(&mut self, i: ImplItemMethod) -> ImplItemMethod {
+ fold_impl_item_method(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_type(&mut self, i: ImplItemType) -> ImplItemType {
+ fold_impl_item_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_index(&mut self, i: Index) -> Index {
+ fold_index(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item(&mut self, i: Item) -> Item {
+ fold_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_const(&mut self, i: ItemConst) -> ItemConst {
+ fold_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_enum(&mut self, i: ItemEnum) -> ItemEnum {
+ fold_item_enum(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_extern_crate(&mut self, i: ItemExternCrate) -> ItemExternCrate {
+ fold_item_extern_crate(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_fn(&mut self, i: ItemFn) -> ItemFn {
+ fold_item_fn(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_foreign_mod(&mut self, i: ItemForeignMod) -> ItemForeignMod {
+ fold_item_foreign_mod(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_impl(&mut self, i: ItemImpl) -> ItemImpl {
+ fold_item_impl(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_macro(&mut self, i: ItemMacro) -> ItemMacro {
+ fold_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_macro2(&mut self, i: ItemMacro2) -> ItemMacro2 {
+ fold_item_macro2(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_mod(&mut self, i: ItemMod) -> ItemMod {
+ fold_item_mod(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_static(&mut self, i: ItemStatic) -> ItemStatic {
+ fold_item_static(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_struct(&mut self, i: ItemStruct) -> ItemStruct {
+ fold_item_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_trait(&mut self, i: ItemTrait) -> ItemTrait {
+ fold_item_trait(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_trait_alias(&mut self, i: ItemTraitAlias) -> ItemTraitAlias {
+ fold_item_trait_alias(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_type(&mut self, i: ItemType) -> ItemType {
+ fold_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_union(&mut self, i: ItemUnion) -> ItemUnion {
+ fold_item_union(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_use(&mut self, i: ItemUse) -> ItemUse {
+ fold_item_use(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_label(&mut self, i: Label) -> Label {
+ fold_label(self, i)
+ }
+ fn fold_lifetime(&mut self, i: Lifetime) -> Lifetime {
+ fold_lifetime(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lifetime_def(&mut self, i: LifetimeDef) -> LifetimeDef {
+ fold_lifetime_def(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lit(&mut self, i: Lit) -> Lit {
+ fold_lit(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lit_bool(&mut self, i: LitBool) -> LitBool {
+ fold_lit_bool(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lit_byte(&mut self, i: LitByte) -> LitByte {
+ fold_lit_byte(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lit_byte_str(&mut self, i: LitByteStr) -> LitByteStr {
+ fold_lit_byte_str(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lit_char(&mut self, i: LitChar) -> LitChar {
+ fold_lit_char(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lit_float(&mut self, i: LitFloat) -> LitFloat {
+ fold_lit_float(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lit_int(&mut self, i: LitInt) -> LitInt {
+ fold_lit_int(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_lit_str(&mut self, i: LitStr) -> LitStr {
+ fold_lit_str(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_local(&mut self, i: Local) -> Local {
+ fold_local(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_macro(&mut self, i: Macro) -> Macro {
+ fold_macro(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_macro_delimiter(&mut self, i: MacroDelimiter) -> MacroDelimiter {
+ fold_macro_delimiter(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_member(&mut self, i: Member) -> Member {
+ fold_member(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_meta(&mut self, i: Meta) -> Meta {
+ fold_meta(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_meta_list(&mut self, i: MetaList) -> MetaList {
+ fold_meta_list(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_meta_name_value(&mut self, i: MetaNameValue) -> MetaNameValue {
+ fold_meta_name_value(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_method_turbofish(&mut self, i: MethodTurbofish) -> MethodTurbofish {
+ fold_method_turbofish(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_nested_meta(&mut self, i: NestedMeta) -> NestedMeta {
+ fold_nested_meta(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_parenthesized_generic_arguments(
+ &mut self,
+ i: ParenthesizedGenericArguments,
+ ) -> ParenthesizedGenericArguments {
+ fold_parenthesized_generic_arguments(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat(&mut self, i: Pat) -> Pat {
+ fold_pat(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_box(&mut self, i: PatBox) -> PatBox {
+ fold_pat_box(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_ident(&mut self, i: PatIdent) -> PatIdent {
+ fold_pat_ident(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_lit(&mut self, i: PatLit) -> PatLit {
+ fold_pat_lit(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_macro(&mut self, i: PatMacro) -> PatMacro {
+ fold_pat_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_or(&mut self, i: PatOr) -> PatOr {
+ fold_pat_or(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_path(&mut self, i: PatPath) -> PatPath {
+ fold_pat_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_range(&mut self, i: PatRange) -> PatRange {
+ fold_pat_range(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_reference(&mut self, i: PatReference) -> PatReference {
+ fold_pat_reference(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_rest(&mut self, i: PatRest) -> PatRest {
+ fold_pat_rest(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_slice(&mut self, i: PatSlice) -> PatSlice {
+ fold_pat_slice(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_struct(&mut self, i: PatStruct) -> PatStruct {
+ fold_pat_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_tuple(&mut self, i: PatTuple) -> PatTuple {
+ fold_pat_tuple(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_tuple_struct(&mut self, i: PatTupleStruct) -> PatTupleStruct {
+ fold_pat_tuple_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_type(&mut self, i: PatType) -> PatType {
+ fold_pat_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_pat_wild(&mut self, i: PatWild) -> PatWild {
+ fold_pat_wild(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_path(&mut self, i: Path) -> Path {
+ fold_path(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_path_arguments(&mut self, i: PathArguments) -> PathArguments {
+ fold_path_arguments(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_path_segment(&mut self, i: PathSegment) -> PathSegment {
+ fold_path_segment(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_predicate_eq(&mut self, i: PredicateEq) -> PredicateEq {
+ fold_predicate_eq(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_predicate_lifetime(&mut self, i: PredicateLifetime) -> PredicateLifetime {
+ fold_predicate_lifetime(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_predicate_type(&mut self, i: PredicateType) -> PredicateType {
+ fold_predicate_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_qself(&mut self, i: QSelf) -> QSelf {
+ fold_qself(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_range_limits(&mut self, i: RangeLimits) -> RangeLimits {
+ fold_range_limits(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_receiver(&mut self, i: Receiver) -> Receiver {
+ fold_receiver(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_return_type(&mut self, i: ReturnType) -> ReturnType {
+ fold_return_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_signature(&mut self, i: Signature) -> Signature {
+ fold_signature(self, i)
+ }
+ fn fold_span(&mut self, i: Span) -> Span {
+ fold_span(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_stmt(&mut self, i: Stmt) -> Stmt {
+ fold_stmt(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_trait_bound(&mut self, i: TraitBound) -> TraitBound {
+ fold_trait_bound(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_trait_bound_modifier(&mut self, i: TraitBoundModifier) -> TraitBoundModifier {
+ fold_trait_bound_modifier(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item(&mut self, i: TraitItem) -> TraitItem {
+ fold_trait_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_const(&mut self, i: TraitItemConst) -> TraitItemConst {
+ fold_trait_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_macro(&mut self, i: TraitItemMacro) -> TraitItemMacro {
+ fold_trait_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_method(&mut self, i: TraitItemMethod) -> TraitItemMethod {
+ fold_trait_item_method(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_type(&mut self, i: TraitItemType) -> TraitItemType {
+ fold_trait_item_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type(&mut self, i: Type) -> Type {
+ fold_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_array(&mut self, i: TypeArray) -> TypeArray {
+ fold_type_array(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_bare_fn(&mut self, i: TypeBareFn) -> TypeBareFn {
+ fold_type_bare_fn(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_group(&mut self, i: TypeGroup) -> TypeGroup {
+ fold_type_group(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_impl_trait(&mut self, i: TypeImplTrait) -> TypeImplTrait {
+ fold_type_impl_trait(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_infer(&mut self, i: TypeInfer) -> TypeInfer {
+ fold_type_infer(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_macro(&mut self, i: TypeMacro) -> TypeMacro {
+ fold_type_macro(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_never(&mut self, i: TypeNever) -> TypeNever {
+ fold_type_never(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_param(&mut self, i: TypeParam) -> TypeParam {
+ fold_type_param(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_param_bound(&mut self, i: TypeParamBound) -> TypeParamBound {
+ fold_type_param_bound(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_paren(&mut self, i: TypeParen) -> TypeParen {
+ fold_type_paren(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_path(&mut self, i: TypePath) -> TypePath {
+ fold_type_path(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_ptr(&mut self, i: TypePtr) -> TypePtr {
+ fold_type_ptr(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_reference(&mut self, i: TypeReference) -> TypeReference {
+ fold_type_reference(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_slice(&mut self, i: TypeSlice) -> TypeSlice {
+ fold_type_slice(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_trait_object(&mut self, i: TypeTraitObject) -> TypeTraitObject {
+ fold_type_trait_object(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_type_tuple(&mut self, i: TypeTuple) -> TypeTuple {
+ fold_type_tuple(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_un_op(&mut self, i: UnOp) -> UnOp {
+ fold_un_op(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_glob(&mut self, i: UseGlob) -> UseGlob {
+ fold_use_glob(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_group(&mut self, i: UseGroup) -> UseGroup {
+ fold_use_group(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_name(&mut self, i: UseName) -> UseName {
+ fold_use_name(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_path(&mut self, i: UsePath) -> UsePath {
+ fold_use_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_rename(&mut self, i: UseRename) -> UseRename {
+ fold_use_rename(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_tree(&mut self, i: UseTree) -> UseTree {
+ fold_use_tree(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_variadic(&mut self, i: Variadic) -> Variadic {
+ fold_variadic(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_variant(&mut self, i: Variant) -> Variant {
+ fold_variant(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_vis_crate(&mut self, i: VisCrate) -> VisCrate {
+ fold_vis_crate(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_vis_public(&mut self, i: VisPublic) -> VisPublic {
+ fold_vis_public(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_vis_restricted(&mut self, i: VisRestricted) -> VisRestricted {
+ fold_vis_restricted(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_visibility(&mut self, i: Visibility) -> Visibility {
+ fold_visibility(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_where_clause(&mut self, i: WhereClause) -> WhereClause {
+ fold_where_clause(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn fold_where_predicate(&mut self, i: WherePredicate) -> WherePredicate {
+ fold_where_predicate(self, i)
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_abi<F>(f: &mut F, node: Abi) -> Abi
+where
+ F: Fold + ?Sized,
+{
+ Abi {
+ extern_token: Token![extern](tokens_helper(f, &node.extern_token.span)),
+ name: (node.name).map(|it| f.fold_lit_str(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_angle_bracketed_generic_arguments<F>(
+ f: &mut F,
+ node: AngleBracketedGenericArguments,
+) -> AngleBracketedGenericArguments
+where
+ F: Fold + ?Sized,
+{
+ AngleBracketedGenericArguments {
+ colon2_token: (node.colon2_token).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))),
+ lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)),
+ args: FoldHelper::lift(node.args, |it| f.fold_generic_argument(it)),
+ gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_arm<F>(f: &mut F, node: Arm) -> Arm
+where
+ F: Fold + ?Sized,
+{
+ Arm {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ pat: f.fold_pat(node.pat),
+ guard: (node.guard).map(|it| {
+ (
+ Token![if](tokens_helper(f, &(it).0.span)),
+ Box::new(f.fold_expr(*(it).1)),
+ )
+ }),
+ fat_arrow_token: Token ! [ => ](tokens_helper(f, &node.fat_arrow_token.spans)),
+ body: Box::new(f.fold_expr(*node.body)),
+ comma: (node.comma).map(|it| Token ! [ , ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_attr_style<F>(f: &mut F, node: AttrStyle) -> AttrStyle
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ AttrStyle::Outer => AttrStyle::Outer,
+ AttrStyle::Inner(_binding_0) => {
+ AttrStyle::Inner(Token![!](tokens_helper(f, &_binding_0.spans)))
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_attribute<F>(f: &mut F, node: Attribute) -> Attribute
+where
+ F: Fold + ?Sized,
+{
+ Attribute {
+ pound_token: Token ! [ # ](tokens_helper(f, &node.pound_token.spans)),
+ style: f.fold_attr_style(node.style),
+ bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)),
+ path: f.fold_path(node.path),
+ tokens: node.tokens,
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_bare_fn_arg<F>(f: &mut F, node: BareFnArg) -> BareFnArg
+where
+ F: Fold + ?Sized,
+{
+ BareFnArg {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ name: (node.name).map(|it| {
+ (
+ f.fold_ident((it).0),
+ Token ! [ : ](tokens_helper(f, &(it).1.spans)),
+ )
+ }),
+ ty: f.fold_type(node.ty),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_bin_op<F>(f: &mut F, node: BinOp) -> BinOp
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ BinOp::Add(_binding_0) => BinOp::Add(Token ! [ + ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Sub(_binding_0) => BinOp::Sub(Token ! [ - ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Mul(_binding_0) => BinOp::Mul(Token ! [ * ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Div(_binding_0) => BinOp::Div(Token ! [ / ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Rem(_binding_0) => BinOp::Rem(Token ! [ % ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::And(_binding_0) => BinOp::And(Token ! [ && ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Or(_binding_0) => BinOp::Or(Token ! [ || ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::BitXor(_binding_0) => {
+ BinOp::BitXor(Token ! [ ^ ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::BitAnd(_binding_0) => {
+ BinOp::BitAnd(Token ! [ & ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::BitOr(_binding_0) => {
+ BinOp::BitOr(Token ! [ | ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::Shl(_binding_0) => BinOp::Shl(Token ! [ << ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Shr(_binding_0) => BinOp::Shr(Token ! [ >> ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Eq(_binding_0) => BinOp::Eq(Token ! [ == ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Lt(_binding_0) => BinOp::Lt(Token ! [ < ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Le(_binding_0) => BinOp::Le(Token ! [ <= ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Ne(_binding_0) => BinOp::Ne(Token ! [ != ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Ge(_binding_0) => BinOp::Ge(Token ! [ >= ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::Gt(_binding_0) => BinOp::Gt(Token ! [ > ](tokens_helper(f, &_binding_0.spans))),
+ BinOp::AddEq(_binding_0) => {
+ BinOp::AddEq(Token ! [ += ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::SubEq(_binding_0) => {
+ BinOp::SubEq(Token ! [ -= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::MulEq(_binding_0) => {
+ BinOp::MulEq(Token ! [ *= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::DivEq(_binding_0) => {
+ BinOp::DivEq(Token ! [ /= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::RemEq(_binding_0) => {
+ BinOp::RemEq(Token ! [ %= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::BitXorEq(_binding_0) => {
+ BinOp::BitXorEq(Token ! [ ^= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::BitAndEq(_binding_0) => {
+ BinOp::BitAndEq(Token ! [ &= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::BitOrEq(_binding_0) => {
+ BinOp::BitOrEq(Token ! [ |= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::ShlEq(_binding_0) => {
+ BinOp::ShlEq(Token ! [ <<= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ BinOp::ShrEq(_binding_0) => {
+ BinOp::ShrEq(Token ! [ >>= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_binding<F>(f: &mut F, node: Binding) -> Binding
+where
+ F: Fold + ?Sized,
+{
+ Binding {
+ ident: f.fold_ident(node.ident),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ ty: f.fold_type(node.ty),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_block<F>(f: &mut F, node: Block) -> Block
+where
+ F: Fold + ?Sized,
+{
+ Block {
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ stmts: FoldHelper::lift(node.stmts, |it| f.fold_stmt(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_bound_lifetimes<F>(f: &mut F, node: BoundLifetimes) -> BoundLifetimes
+where
+ F: Fold + ?Sized,
+{
+ BoundLifetimes {
+ for_token: Token![for](tokens_helper(f, &node.for_token.span)),
+ lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)),
+ lifetimes: FoldHelper::lift(node.lifetimes, |it| f.fold_lifetime_def(it)),
+ gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_const_param<F>(f: &mut F, node: ConstParam) -> ConstParam
+where
+ F: Fold + ?Sized,
+{
+ ConstParam {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ const_token: Token![const](tokens_helper(f, &node.const_token.span)),
+ ident: f.fold_ident(node.ident),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ ty: f.fold_type(node.ty),
+ eq_token: (node.eq_token).map(|it| Token ! [ = ](tokens_helper(f, &it.spans))),
+ default: (node.default).map(|it| f.fold_expr(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_constraint<F>(f: &mut F, node: Constraint) -> Constraint
+where
+ F: Fold + ?Sized,
+{
+ Constraint {
+ ident: f.fold_ident(node.ident),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_data<F>(f: &mut F, node: Data) -> Data
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Data::Struct(_binding_0) => Data::Struct(f.fold_data_struct(_binding_0)),
+ Data::Enum(_binding_0) => Data::Enum(f.fold_data_enum(_binding_0)),
+ Data::Union(_binding_0) => Data::Union(f.fold_data_union(_binding_0)),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_data_enum<F>(f: &mut F, node: DataEnum) -> DataEnum
+where
+ F: Fold + ?Sized,
+{
+ DataEnum {
+ enum_token: Token![enum](tokens_helper(f, &node.enum_token.span)),
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ variants: FoldHelper::lift(node.variants, |it| f.fold_variant(it)),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_data_struct<F>(f: &mut F, node: DataStruct) -> DataStruct
+where
+ F: Fold + ?Sized,
+{
+ DataStruct {
+ struct_token: Token![struct](tokens_helper(f, &node.struct_token.span)),
+ fields: f.fold_fields(node.fields),
+ semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_data_union<F>(f: &mut F, node: DataUnion) -> DataUnion
+where
+ F: Fold + ?Sized,
+{
+ DataUnion {
+ union_token: Token![union](tokens_helper(f, &node.union_token.span)),
+ fields: f.fold_fields_named(node.fields),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_derive_input<F>(f: &mut F, node: DeriveInput) -> DeriveInput
+where
+ F: Fold + ?Sized,
+{
+ DeriveInput {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ data: f.fold_data(node.data),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr<F>(f: &mut F, node: Expr) -> Expr
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Expr::Array(_binding_0) => Expr::Array(full!(f.fold_expr_array(_binding_0))),
+ Expr::Assign(_binding_0) => Expr::Assign(full!(f.fold_expr_assign(_binding_0))),
+ Expr::AssignOp(_binding_0) => Expr::AssignOp(full!(f.fold_expr_assign_op(_binding_0))),
+ Expr::Async(_binding_0) => Expr::Async(full!(f.fold_expr_async(_binding_0))),
+ Expr::Await(_binding_0) => Expr::Await(full!(f.fold_expr_await(_binding_0))),
+ Expr::Binary(_binding_0) => Expr::Binary(f.fold_expr_binary(_binding_0)),
+ Expr::Block(_binding_0) => Expr::Block(full!(f.fold_expr_block(_binding_0))),
+ Expr::Box(_binding_0) => Expr::Box(full!(f.fold_expr_box(_binding_0))),
+ Expr::Break(_binding_0) => Expr::Break(full!(f.fold_expr_break(_binding_0))),
+ Expr::Call(_binding_0) => Expr::Call(f.fold_expr_call(_binding_0)),
+ Expr::Cast(_binding_0) => Expr::Cast(f.fold_expr_cast(_binding_0)),
+ Expr::Closure(_binding_0) => Expr::Closure(full!(f.fold_expr_closure(_binding_0))),
+ Expr::Continue(_binding_0) => Expr::Continue(full!(f.fold_expr_continue(_binding_0))),
+ Expr::Field(_binding_0) => Expr::Field(f.fold_expr_field(_binding_0)),
+ Expr::ForLoop(_binding_0) => Expr::ForLoop(full!(f.fold_expr_for_loop(_binding_0))),
+ Expr::Group(_binding_0) => Expr::Group(full!(f.fold_expr_group(_binding_0))),
+ Expr::If(_binding_0) => Expr::If(full!(f.fold_expr_if(_binding_0))),
+ Expr::Index(_binding_0) => Expr::Index(f.fold_expr_index(_binding_0)),
+ Expr::Let(_binding_0) => Expr::Let(full!(f.fold_expr_let(_binding_0))),
+ Expr::Lit(_binding_0) => Expr::Lit(f.fold_expr_lit(_binding_0)),
+ Expr::Loop(_binding_0) => Expr::Loop(full!(f.fold_expr_loop(_binding_0))),
+ Expr::Macro(_binding_0) => Expr::Macro(full!(f.fold_expr_macro(_binding_0))),
+ Expr::Match(_binding_0) => Expr::Match(full!(f.fold_expr_match(_binding_0))),
+ Expr::MethodCall(_binding_0) => {
+ Expr::MethodCall(full!(f.fold_expr_method_call(_binding_0)))
+ }
+ Expr::Paren(_binding_0) => Expr::Paren(f.fold_expr_paren(_binding_0)),
+ Expr::Path(_binding_0) => Expr::Path(f.fold_expr_path(_binding_0)),
+ Expr::Range(_binding_0) => Expr::Range(full!(f.fold_expr_range(_binding_0))),
+ Expr::Reference(_binding_0) => Expr::Reference(full!(f.fold_expr_reference(_binding_0))),
+ Expr::Repeat(_binding_0) => Expr::Repeat(full!(f.fold_expr_repeat(_binding_0))),
+ Expr::Return(_binding_0) => Expr::Return(full!(f.fold_expr_return(_binding_0))),
+ Expr::Struct(_binding_0) => Expr::Struct(full!(f.fold_expr_struct(_binding_0))),
+ Expr::Try(_binding_0) => Expr::Try(full!(f.fold_expr_try(_binding_0))),
+ Expr::TryBlock(_binding_0) => Expr::TryBlock(full!(f.fold_expr_try_block(_binding_0))),
+ Expr::Tuple(_binding_0) => Expr::Tuple(full!(f.fold_expr_tuple(_binding_0))),
+ Expr::Type(_binding_0) => Expr::Type(full!(f.fold_expr_type(_binding_0))),
+ Expr::Unary(_binding_0) => Expr::Unary(f.fold_expr_unary(_binding_0)),
+ Expr::Unsafe(_binding_0) => Expr::Unsafe(full!(f.fold_expr_unsafe(_binding_0))),
+ Expr::Verbatim(_binding_0) => Expr::Verbatim(_binding_0),
+ Expr::While(_binding_0) => Expr::While(full!(f.fold_expr_while(_binding_0))),
+ Expr::Yield(_binding_0) => Expr::Yield(full!(f.fold_expr_yield(_binding_0))),
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_array<F>(f: &mut F, node: ExprArray) -> ExprArray
+where
+ F: Fold + ?Sized,
+{
+ ExprArray {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)),
+ elems: FoldHelper::lift(node.elems, |it| f.fold_expr(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_assign<F>(f: &mut F, node: ExprAssign) -> ExprAssign
+where
+ F: Fold + ?Sized,
+{
+ ExprAssign {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ left: Box::new(f.fold_expr(*node.left)),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ right: Box::new(f.fold_expr(*node.right)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_assign_op<F>(f: &mut F, node: ExprAssignOp) -> ExprAssignOp
+where
+ F: Fold + ?Sized,
+{
+ ExprAssignOp {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ left: Box::new(f.fold_expr(*node.left)),
+ op: f.fold_bin_op(node.op),
+ right: Box::new(f.fold_expr(*node.right)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_async<F>(f: &mut F, node: ExprAsync) -> ExprAsync
+where
+ F: Fold + ?Sized,
+{
+ ExprAsync {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ async_token: Token![async](tokens_helper(f, &node.async_token.span)),
+ capture: (node.capture).map(|it| Token![move](tokens_helper(f, &it.span))),
+ block: f.fold_block(node.block),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_await<F>(f: &mut F, node: ExprAwait) -> ExprAwait
+where
+ F: Fold + ?Sized,
+{
+ ExprAwait {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ base: Box::new(f.fold_expr(*node.base)),
+ dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)),
+ await_token: crate::token::Await(tokens_helper(f, &node.await_token.span)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_binary<F>(f: &mut F, node: ExprBinary) -> ExprBinary
+where
+ F: Fold + ?Sized,
+{
+ ExprBinary {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ left: Box::new(f.fold_expr(*node.left)),
+ op: f.fold_bin_op(node.op),
+ right: Box::new(f.fold_expr(*node.right)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_block<F>(f: &mut F, node: ExprBlock) -> ExprBlock
+where
+ F: Fold + ?Sized,
+{
+ ExprBlock {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ label: (node.label).map(|it| f.fold_label(it)),
+ block: f.fold_block(node.block),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_box<F>(f: &mut F, node: ExprBox) -> ExprBox
+where
+ F: Fold + ?Sized,
+{
+ ExprBox {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ box_token: Token![box](tokens_helper(f, &node.box_token.span)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_break<F>(f: &mut F, node: ExprBreak) -> ExprBreak
+where
+ F: Fold + ?Sized,
+{
+ ExprBreak {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ break_token: Token![break](tokens_helper(f, &node.break_token.span)),
+ label: (node.label).map(|it| f.fold_lifetime(it)),
+ expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_call<F>(f: &mut F, node: ExprCall) -> ExprCall
+where
+ F: Fold + ?Sized,
+{
+ ExprCall {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ func: Box::new(f.fold_expr(*node.func)),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ args: FoldHelper::lift(node.args, |it| f.fold_expr(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_cast<F>(f: &mut F, node: ExprCast) -> ExprCast
+where
+ F: Fold + ?Sized,
+{
+ ExprCast {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ as_token: Token![as](tokens_helper(f, &node.as_token.span)),
+ ty: Box::new(f.fold_type(*node.ty)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_closure<F>(f: &mut F, node: ExprClosure) -> ExprClosure
+where
+ F: Fold + ?Sized,
+{
+ ExprClosure {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ asyncness: (node.asyncness).map(|it| Token![async](tokens_helper(f, &it.span))),
+ movability: (node.movability).map(|it| Token![static](tokens_helper(f, &it.span))),
+ capture: (node.capture).map(|it| Token![move](tokens_helper(f, &it.span))),
+ or1_token: Token ! [ | ](tokens_helper(f, &node.or1_token.spans)),
+ inputs: FoldHelper::lift(node.inputs, |it| f.fold_pat(it)),
+ or2_token: Token ! [ | ](tokens_helper(f, &node.or2_token.spans)),
+ output: f.fold_return_type(node.output),
+ body: Box::new(f.fold_expr(*node.body)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_continue<F>(f: &mut F, node: ExprContinue) -> ExprContinue
+where
+ F: Fold + ?Sized,
+{
+ ExprContinue {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ continue_token: Token![continue](tokens_helper(f, &node.continue_token.span)),
+ label: (node.label).map(|it| f.fold_lifetime(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_field<F>(f: &mut F, node: ExprField) -> ExprField
+where
+ F: Fold + ?Sized,
+{
+ ExprField {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ base: Box::new(f.fold_expr(*node.base)),
+ dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)),
+ member: f.fold_member(node.member),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_for_loop<F>(f: &mut F, node: ExprForLoop) -> ExprForLoop
+where
+ F: Fold + ?Sized,
+{
+ ExprForLoop {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ label: (node.label).map(|it| f.fold_label(it)),
+ for_token: Token![for](tokens_helper(f, &node.for_token.span)),
+ pat: f.fold_pat(node.pat),
+ in_token: Token![in](tokens_helper(f, &node.in_token.span)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ body: f.fold_block(node.body),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_group<F>(f: &mut F, node: ExprGroup) -> ExprGroup
+where
+ F: Fold + ?Sized,
+{
+ ExprGroup {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ group_token: Group(tokens_helper(f, &node.group_token.span)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_if<F>(f: &mut F, node: ExprIf) -> ExprIf
+where
+ F: Fold + ?Sized,
+{
+ ExprIf {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ if_token: Token![if](tokens_helper(f, &node.if_token.span)),
+ cond: Box::new(f.fold_expr(*node.cond)),
+ then_branch: f.fold_block(node.then_branch),
+ else_branch: (node.else_branch).map(|it| {
+ (
+ Token![else](tokens_helper(f, &(it).0.span)),
+ Box::new(f.fold_expr(*(it).1)),
+ )
+ }),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_index<F>(f: &mut F, node: ExprIndex) -> ExprIndex
+where
+ F: Fold + ?Sized,
+{
+ ExprIndex {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)),
+ index: Box::new(f.fold_expr(*node.index)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_let<F>(f: &mut F, node: ExprLet) -> ExprLet
+where
+ F: Fold + ?Sized,
+{
+ ExprLet {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ let_token: Token![let](tokens_helper(f, &node.let_token.span)),
+ pat: f.fold_pat(node.pat),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_lit<F>(f: &mut F, node: ExprLit) -> ExprLit
+where
+ F: Fold + ?Sized,
+{
+ ExprLit {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ lit: f.fold_lit(node.lit),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_loop<F>(f: &mut F, node: ExprLoop) -> ExprLoop
+where
+ F: Fold + ?Sized,
+{
+ ExprLoop {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ label: (node.label).map(|it| f.fold_label(it)),
+ loop_token: Token![loop](tokens_helper(f, &node.loop_token.span)),
+ body: f.fold_block(node.body),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_macro<F>(f: &mut F, node: ExprMacro) -> ExprMacro
+where
+ F: Fold + ?Sized,
+{
+ ExprMacro {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ mac: f.fold_macro(node.mac),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_match<F>(f: &mut F, node: ExprMatch) -> ExprMatch
+where
+ F: Fold + ?Sized,
+{
+ ExprMatch {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ match_token: Token![match](tokens_helper(f, &node.match_token.span)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ arms: FoldHelper::lift(node.arms, |it| f.fold_arm(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_method_call<F>(f: &mut F, node: ExprMethodCall) -> ExprMethodCall
+where
+ F: Fold + ?Sized,
+{
+ ExprMethodCall {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ receiver: Box::new(f.fold_expr(*node.receiver)),
+ dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)),
+ method: f.fold_ident(node.method),
+ turbofish: (node.turbofish).map(|it| f.fold_method_turbofish(it)),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ args: FoldHelper::lift(node.args, |it| f.fold_expr(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_paren<F>(f: &mut F, node: ExprParen) -> ExprParen
+where
+ F: Fold + ?Sized,
+{
+ ExprParen {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_path<F>(f: &mut F, node: ExprPath) -> ExprPath
+where
+ F: Fold + ?Sized,
+{
+ ExprPath {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ qself: (node.qself).map(|it| f.fold_qself(it)),
+ path: f.fold_path(node.path),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_range<F>(f: &mut F, node: ExprRange) -> ExprRange
+where
+ F: Fold + ?Sized,
+{
+ ExprRange {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ from: (node.from).map(|it| Box::new(f.fold_expr(*it))),
+ limits: f.fold_range_limits(node.limits),
+ to: (node.to).map(|it| Box::new(f.fold_expr(*it))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_reference<F>(f: &mut F, node: ExprReference) -> ExprReference
+where
+ F: Fold + ?Sized,
+{
+ ExprReference {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)),
+ raw: node.raw,
+ mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_repeat<F>(f: &mut F, node: ExprRepeat) -> ExprRepeat
+where
+ F: Fold + ?Sized,
+{
+ ExprRepeat {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ len: Box::new(f.fold_expr(*node.len)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_return<F>(f: &mut F, node: ExprReturn) -> ExprReturn
+where
+ F: Fold + ?Sized,
+{
+ ExprReturn {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ return_token: Token![return](tokens_helper(f, &node.return_token.span)),
+ expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_struct<F>(f: &mut F, node: ExprStruct) -> ExprStruct
+where
+ F: Fold + ?Sized,
+{
+ ExprStruct {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ path: f.fold_path(node.path),
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ fields: FoldHelper::lift(node.fields, |it| f.fold_field_value(it)),
+ dot2_token: (node.dot2_token).map(|it| Token![..](tokens_helper(f, &it.spans))),
+ rest: (node.rest).map(|it| Box::new(f.fold_expr(*it))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_try<F>(f: &mut F, node: ExprTry) -> ExprTry
+where
+ F: Fold + ?Sized,
+{
+ ExprTry {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ question_token: Token ! [ ? ](tokens_helper(f, &node.question_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_try_block<F>(f: &mut F, node: ExprTryBlock) -> ExprTryBlock
+where
+ F: Fold + ?Sized,
+{
+ ExprTryBlock {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ try_token: Token![try](tokens_helper(f, &node.try_token.span)),
+ block: f.fold_block(node.block),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_tuple<F>(f: &mut F, node: ExprTuple) -> ExprTuple
+where
+ F: Fold + ?Sized,
+{
+ ExprTuple {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ elems: FoldHelper::lift(node.elems, |it| f.fold_expr(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_type<F>(f: &mut F, node: ExprType) -> ExprType
+where
+ F: Fold + ?Sized,
+{
+ ExprType {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ ty: Box::new(f.fold_type(*node.ty)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_expr_unary<F>(f: &mut F, node: ExprUnary) -> ExprUnary
+where
+ F: Fold + ?Sized,
+{
+ ExprUnary {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ op: f.fold_un_op(node.op),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_unsafe<F>(f: &mut F, node: ExprUnsafe) -> ExprUnsafe
+where
+ F: Fold + ?Sized,
+{
+ ExprUnsafe {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ unsafe_token: Token![unsafe](tokens_helper(f, &node.unsafe_token.span)),
+ block: f.fold_block(node.block),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_while<F>(f: &mut F, node: ExprWhile) -> ExprWhile
+where
+ F: Fold + ?Sized,
+{
+ ExprWhile {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ label: (node.label).map(|it| f.fold_label(it)),
+ while_token: Token![while](tokens_helper(f, &node.while_token.span)),
+ cond: Box::new(f.fold_expr(*node.cond)),
+ body: f.fold_block(node.body),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_expr_yield<F>(f: &mut F, node: ExprYield) -> ExprYield
+where
+ F: Fold + ?Sized,
+{
+ ExprYield {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ yield_token: Token![yield](tokens_helper(f, &node.yield_token.span)),
+ expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_field<F>(f: &mut F, node: Field) -> Field
+where
+ F: Fold + ?Sized,
+{
+ Field {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ ident: (node.ident).map(|it| f.fold_ident(it)),
+ colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))),
+ ty: f.fold_type(node.ty),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_field_pat<F>(f: &mut F, node: FieldPat) -> FieldPat
+where
+ F: Fold + ?Sized,
+{
+ FieldPat {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ member: f.fold_member(node.member),
+ colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))),
+ pat: Box::new(f.fold_pat(*node.pat)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_field_value<F>(f: &mut F, node: FieldValue) -> FieldValue
+where
+ F: Fold + ?Sized,
+{
+ FieldValue {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ member: f.fold_member(node.member),
+ colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))),
+ expr: f.fold_expr(node.expr),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_fields<F>(f: &mut F, node: Fields) -> Fields
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Fields::Named(_binding_0) => Fields::Named(f.fold_fields_named(_binding_0)),
+ Fields::Unnamed(_binding_0) => Fields::Unnamed(f.fold_fields_unnamed(_binding_0)),
+ Fields::Unit => Fields::Unit,
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_fields_named<F>(f: &mut F, node: FieldsNamed) -> FieldsNamed
+where
+ F: Fold + ?Sized,
+{
+ FieldsNamed {
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ named: FoldHelper::lift(node.named, |it| f.fold_field(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_fields_unnamed<F>(f: &mut F, node: FieldsUnnamed) -> FieldsUnnamed
+where
+ F: Fold + ?Sized,
+{
+ FieldsUnnamed {
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ unnamed: FoldHelper::lift(node.unnamed, |it| f.fold_field(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_file<F>(f: &mut F, node: File) -> File
+where
+ F: Fold + ?Sized,
+{
+ File {
+ shebang: node.shebang,
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ items: FoldHelper::lift(node.items, |it| f.fold_item(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_fn_arg<F>(f: &mut F, node: FnArg) -> FnArg
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ FnArg::Receiver(_binding_0) => FnArg::Receiver(f.fold_receiver(_binding_0)),
+ FnArg::Typed(_binding_0) => FnArg::Typed(f.fold_pat_type(_binding_0)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item<F>(f: &mut F, node: ForeignItem) -> ForeignItem
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ ForeignItem::Fn(_binding_0) => ForeignItem::Fn(f.fold_foreign_item_fn(_binding_0)),
+ ForeignItem::Static(_binding_0) => {
+ ForeignItem::Static(f.fold_foreign_item_static(_binding_0))
+ }
+ ForeignItem::Type(_binding_0) => ForeignItem::Type(f.fold_foreign_item_type(_binding_0)),
+ ForeignItem::Macro(_binding_0) => ForeignItem::Macro(f.fold_foreign_item_macro(_binding_0)),
+ ForeignItem::Verbatim(_binding_0) => ForeignItem::Verbatim(_binding_0),
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_fn<F>(f: &mut F, node: ForeignItemFn) -> ForeignItemFn
+where
+ F: Fold + ?Sized,
+{
+ ForeignItemFn {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ sig: f.fold_signature(node.sig),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_macro<F>(f: &mut F, node: ForeignItemMacro) -> ForeignItemMacro
+where
+ F: Fold + ?Sized,
+{
+ ForeignItemMacro {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ mac: f.fold_macro(node.mac),
+ semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_static<F>(f: &mut F, node: ForeignItemStatic) -> ForeignItemStatic
+where
+ F: Fold + ?Sized,
+{
+ ForeignItemStatic {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ static_token: Token![static](tokens_helper(f, &node.static_token.span)),
+ mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+ ident: f.fold_ident(node.ident),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ ty: Box::new(f.fold_type(*node.ty)),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_type<F>(f: &mut F, node: ForeignItemType) -> ForeignItemType
+where
+ F: Fold + ?Sized,
+{
+ ForeignItemType {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ type_token: Token![type](tokens_helper(f, &node.type_token.span)),
+ ident: f.fold_ident(node.ident),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_generic_argument<F>(f: &mut F, node: GenericArgument) -> GenericArgument
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ GenericArgument::Lifetime(_binding_0) => {
+ GenericArgument::Lifetime(f.fold_lifetime(_binding_0))
+ }
+ GenericArgument::Type(_binding_0) => GenericArgument::Type(f.fold_type(_binding_0)),
+ GenericArgument::Binding(_binding_0) => {
+ GenericArgument::Binding(f.fold_binding(_binding_0))
+ }
+ GenericArgument::Constraint(_binding_0) => {
+ GenericArgument::Constraint(f.fold_constraint(_binding_0))
+ }
+ GenericArgument::Const(_binding_0) => GenericArgument::Const(f.fold_expr(_binding_0)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_generic_method_argument<F>(
+ f: &mut F,
+ node: GenericMethodArgument,
+) -> GenericMethodArgument
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ GenericMethodArgument::Type(_binding_0) => {
+ GenericMethodArgument::Type(f.fold_type(_binding_0))
+ }
+ GenericMethodArgument::Const(_binding_0) => {
+ GenericMethodArgument::Const(f.fold_expr(_binding_0))
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_generic_param<F>(f: &mut F, node: GenericParam) -> GenericParam
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ GenericParam::Type(_binding_0) => GenericParam::Type(f.fold_type_param(_binding_0)),
+ GenericParam::Lifetime(_binding_0) => {
+ GenericParam::Lifetime(f.fold_lifetime_def(_binding_0))
+ }
+ GenericParam::Const(_binding_0) => GenericParam::Const(f.fold_const_param(_binding_0)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_generics<F>(f: &mut F, node: Generics) -> Generics
+where
+ F: Fold + ?Sized,
+{
+ Generics {
+ lt_token: (node.lt_token).map(|it| Token ! [ < ](tokens_helper(f, &it.spans))),
+ params: FoldHelper::lift(node.params, |it| f.fold_generic_param(it)),
+ gt_token: (node.gt_token).map(|it| Token ! [ > ](tokens_helper(f, &it.spans))),
+ where_clause: (node.where_clause).map(|it| f.fold_where_clause(it)),
+ }
+}
+pub fn fold_ident<F>(f: &mut F, node: Ident) -> Ident
+where
+ F: Fold + ?Sized,
+{
+ let mut node = node;
+ let span = f.fold_span(node.span());
+ node.set_span(span);
+ node
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item<F>(f: &mut F, node: ImplItem) -> ImplItem
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ ImplItem::Const(_binding_0) => ImplItem::Const(f.fold_impl_item_const(_binding_0)),
+ ImplItem::Method(_binding_0) => ImplItem::Method(f.fold_impl_item_method(_binding_0)),
+ ImplItem::Type(_binding_0) => ImplItem::Type(f.fold_impl_item_type(_binding_0)),
+ ImplItem::Macro(_binding_0) => ImplItem::Macro(f.fold_impl_item_macro(_binding_0)),
+ ImplItem::Verbatim(_binding_0) => ImplItem::Verbatim(_binding_0),
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_const<F>(f: &mut F, node: ImplItemConst) -> ImplItemConst
+where
+ F: Fold + ?Sized,
+{
+ ImplItemConst {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))),
+ const_token: Token![const](tokens_helper(f, &node.const_token.span)),
+ ident: f.fold_ident(node.ident),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ ty: f.fold_type(node.ty),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ expr: f.fold_expr(node.expr),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_macro<F>(f: &mut F, node: ImplItemMacro) -> ImplItemMacro
+where
+ F: Fold + ?Sized,
+{
+ ImplItemMacro {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ mac: f.fold_macro(node.mac),
+ semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_method<F>(f: &mut F, node: ImplItemMethod) -> ImplItemMethod
+where
+ F: Fold + ?Sized,
+{
+ ImplItemMethod {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))),
+ sig: f.fold_signature(node.sig),
+ block: f.fold_block(node.block),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_type<F>(f: &mut F, node: ImplItemType) -> ImplItemType
+where
+ F: Fold + ?Sized,
+{
+ ImplItemType {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))),
+ type_token: Token![type](tokens_helper(f, &node.type_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ ty: f.fold_type(node.ty),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_index<F>(f: &mut F, node: Index) -> Index
+where
+ F: Fold + ?Sized,
+{
+ Index {
+ index: node.index,
+ span: f.fold_span(node.span),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item<F>(f: &mut F, node: Item) -> Item
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Item::Const(_binding_0) => Item::Const(f.fold_item_const(_binding_0)),
+ Item::Enum(_binding_0) => Item::Enum(f.fold_item_enum(_binding_0)),
+ Item::ExternCrate(_binding_0) => Item::ExternCrate(f.fold_item_extern_crate(_binding_0)),
+ Item::Fn(_binding_0) => Item::Fn(f.fold_item_fn(_binding_0)),
+ Item::ForeignMod(_binding_0) => Item::ForeignMod(f.fold_item_foreign_mod(_binding_0)),
+ Item::Impl(_binding_0) => Item::Impl(f.fold_item_impl(_binding_0)),
+ Item::Macro(_binding_0) => Item::Macro(f.fold_item_macro(_binding_0)),
+ Item::Macro2(_binding_0) => Item::Macro2(f.fold_item_macro2(_binding_0)),
+ Item::Mod(_binding_0) => Item::Mod(f.fold_item_mod(_binding_0)),
+ Item::Static(_binding_0) => Item::Static(f.fold_item_static(_binding_0)),
+ Item::Struct(_binding_0) => Item::Struct(f.fold_item_struct(_binding_0)),
+ Item::Trait(_binding_0) => Item::Trait(f.fold_item_trait(_binding_0)),
+ Item::TraitAlias(_binding_0) => Item::TraitAlias(f.fold_item_trait_alias(_binding_0)),
+ Item::Type(_binding_0) => Item::Type(f.fold_item_type(_binding_0)),
+ Item::Union(_binding_0) => Item::Union(f.fold_item_union(_binding_0)),
+ Item::Use(_binding_0) => Item::Use(f.fold_item_use(_binding_0)),
+ Item::Verbatim(_binding_0) => Item::Verbatim(_binding_0),
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_const<F>(f: &mut F, node: ItemConst) -> ItemConst
+where
+ F: Fold + ?Sized,
+{
+ ItemConst {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ const_token: Token![const](tokens_helper(f, &node.const_token.span)),
+ ident: f.fold_ident(node.ident),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ ty: Box::new(f.fold_type(*node.ty)),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_enum<F>(f: &mut F, node: ItemEnum) -> ItemEnum
+where
+ F: Fold + ?Sized,
+{
+ ItemEnum {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ enum_token: Token![enum](tokens_helper(f, &node.enum_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ variants: FoldHelper::lift(node.variants, |it| f.fold_variant(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_extern_crate<F>(f: &mut F, node: ItemExternCrate) -> ItemExternCrate
+where
+ F: Fold + ?Sized,
+{
+ ItemExternCrate {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ extern_token: Token![extern](tokens_helper(f, &node.extern_token.span)),
+ crate_token: Token![crate](tokens_helper(f, &node.crate_token.span)),
+ ident: f.fold_ident(node.ident),
+ rename: (node.rename).map(|it| {
+ (
+ Token![as](tokens_helper(f, &(it).0.span)),
+ f.fold_ident((it).1),
+ )
+ }),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_fn<F>(f: &mut F, node: ItemFn) -> ItemFn
+where
+ F: Fold + ?Sized,
+{
+ ItemFn {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ sig: f.fold_signature(node.sig),
+ block: Box::new(f.fold_block(*node.block)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_foreign_mod<F>(f: &mut F, node: ItemForeignMod) -> ItemForeignMod
+where
+ F: Fold + ?Sized,
+{
+ ItemForeignMod {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ abi: f.fold_abi(node.abi),
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ items: FoldHelper::lift(node.items, |it| f.fold_foreign_item(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_impl<F>(f: &mut F, node: ItemImpl) -> ItemImpl
+where
+ F: Fold + ?Sized,
+{
+ ItemImpl {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))),
+ unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))),
+ impl_token: Token![impl](tokens_helper(f, &node.impl_token.span)),
+ generics: f.fold_generics(node.generics),
+ trait_: (node.trait_).map(|it| {
+ (
+ ((it).0).map(|it| Token![!](tokens_helper(f, &it.spans))),
+ f.fold_path((it).1),
+ Token![for](tokens_helper(f, &(it).2.span)),
+ )
+ }),
+ self_ty: Box::new(f.fold_type(*node.self_ty)),
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ items: FoldHelper::lift(node.items, |it| f.fold_impl_item(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_macro<F>(f: &mut F, node: ItemMacro) -> ItemMacro
+where
+ F: Fold + ?Sized,
+{
+ ItemMacro {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ ident: (node.ident).map(|it| f.fold_ident(it)),
+ mac: f.fold_macro(node.mac),
+ semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_macro2<F>(f: &mut F, node: ItemMacro2) -> ItemMacro2
+where
+ F: Fold + ?Sized,
+{
+ ItemMacro2 {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ macro_token: Token![macro](tokens_helper(f, &node.macro_token.span)),
+ ident: f.fold_ident(node.ident),
+ rules: node.rules,
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_mod<F>(f: &mut F, node: ItemMod) -> ItemMod
+where
+ F: Fold + ?Sized,
+{
+ ItemMod {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ mod_token: Token![mod](tokens_helper(f, &node.mod_token.span)),
+ ident: f.fold_ident(node.ident),
+ content: (node.content).map(|it| {
+ (
+ Brace(tokens_helper(f, &(it).0.span)),
+ FoldHelper::lift((it).1, |it| f.fold_item(it)),
+ )
+ }),
+ semi: (node.semi).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_static<F>(f: &mut F, node: ItemStatic) -> ItemStatic
+where
+ F: Fold + ?Sized,
+{
+ ItemStatic {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ static_token: Token![static](tokens_helper(f, &node.static_token.span)),
+ mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+ ident: f.fold_ident(node.ident),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ ty: Box::new(f.fold_type(*node.ty)),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_struct<F>(f: &mut F, node: ItemStruct) -> ItemStruct
+where
+ F: Fold + ?Sized,
+{
+ ItemStruct {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ struct_token: Token![struct](tokens_helper(f, &node.struct_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ fields: f.fold_fields(node.fields),
+ semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_trait<F>(f: &mut F, node: ItemTrait) -> ItemTrait
+where
+ F: Fold + ?Sized,
+{
+ ItemTrait {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))),
+ auto_token: (node.auto_token).map(|it| Token![auto](tokens_helper(f, &it.span))),
+ trait_token: Token![trait](tokens_helper(f, &node.trait_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))),
+ supertraits: FoldHelper::lift(node.supertraits, |it| f.fold_type_param_bound(it)),
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ items: FoldHelper::lift(node.items, |it| f.fold_trait_item(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_trait_alias<F>(f: &mut F, node: ItemTraitAlias) -> ItemTraitAlias
+where
+ F: Fold + ?Sized,
+{
+ ItemTraitAlias {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ trait_token: Token![trait](tokens_helper(f, &node.trait_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_type<F>(f: &mut F, node: ItemType) -> ItemType
+where
+ F: Fold + ?Sized,
+{
+ ItemType {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ type_token: Token![type](tokens_helper(f, &node.type_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ ty: Box::new(f.fold_type(*node.ty)),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_union<F>(f: &mut F, node: ItemUnion) -> ItemUnion
+where
+ F: Fold + ?Sized,
+{
+ ItemUnion {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ union_token: Token![union](tokens_helper(f, &node.union_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ fields: f.fold_fields_named(node.fields),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_use<F>(f: &mut F, node: ItemUse) -> ItemUse
+where
+ F: Fold + ?Sized,
+{
+ ItemUse {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ vis: f.fold_visibility(node.vis),
+ use_token: Token![use](tokens_helper(f, &node.use_token.span)),
+ leading_colon: (node.leading_colon).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))),
+ tree: f.fold_use_tree(node.tree),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_label<F>(f: &mut F, node: Label) -> Label
+where
+ F: Fold + ?Sized,
+{
+ Label {
+ name: f.fold_lifetime(node.name),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ }
+}
+pub fn fold_lifetime<F>(f: &mut F, node: Lifetime) -> Lifetime
+where
+ F: Fold + ?Sized,
+{
+ Lifetime {
+ apostrophe: f.fold_span(node.apostrophe),
+ ident: f.fold_ident(node.ident),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lifetime_def<F>(f: &mut F, node: LifetimeDef) -> LifetimeDef
+where
+ F: Fold + ?Sized,
+{
+ LifetimeDef {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ lifetime: f.fold_lifetime(node.lifetime),
+ colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_lifetime(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lit<F>(f: &mut F, node: Lit) -> Lit
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Lit::Str(_binding_0) => Lit::Str(f.fold_lit_str(_binding_0)),
+ Lit::ByteStr(_binding_0) => Lit::ByteStr(f.fold_lit_byte_str(_binding_0)),
+ Lit::Byte(_binding_0) => Lit::Byte(f.fold_lit_byte(_binding_0)),
+ Lit::Char(_binding_0) => Lit::Char(f.fold_lit_char(_binding_0)),
+ Lit::Int(_binding_0) => Lit::Int(f.fold_lit_int(_binding_0)),
+ Lit::Float(_binding_0) => Lit::Float(f.fold_lit_float(_binding_0)),
+ Lit::Bool(_binding_0) => Lit::Bool(f.fold_lit_bool(_binding_0)),
+ Lit::Verbatim(_binding_0) => Lit::Verbatim(_binding_0),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lit_bool<F>(f: &mut F, node: LitBool) -> LitBool
+where
+ F: Fold + ?Sized,
+{
+ LitBool {
+ value: node.value,
+ span: f.fold_span(node.span),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lit_byte<F>(f: &mut F, node: LitByte) -> LitByte
+where
+ F: Fold + ?Sized,
+{
+ let span = f.fold_span(node.span());
+ let mut node = node;
+ node.set_span(span);
+ node
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lit_byte_str<F>(f: &mut F, node: LitByteStr) -> LitByteStr
+where
+ F: Fold + ?Sized,
+{
+ let span = f.fold_span(node.span());
+ let mut node = node;
+ node.set_span(span);
+ node
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lit_char<F>(f: &mut F, node: LitChar) -> LitChar
+where
+ F: Fold + ?Sized,
+{
+ let span = f.fold_span(node.span());
+ let mut node = node;
+ node.set_span(span);
+ node
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lit_float<F>(f: &mut F, node: LitFloat) -> LitFloat
+where
+ F: Fold + ?Sized,
+{
+ let span = f.fold_span(node.span());
+ let mut node = node;
+ node.set_span(span);
+ node
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lit_int<F>(f: &mut F, node: LitInt) -> LitInt
+where
+ F: Fold + ?Sized,
+{
+ let span = f.fold_span(node.span());
+ let mut node = node;
+ node.set_span(span);
+ node
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_lit_str<F>(f: &mut F, node: LitStr) -> LitStr
+where
+ F: Fold + ?Sized,
+{
+ let span = f.fold_span(node.span());
+ let mut node = node;
+ node.set_span(span);
+ node
+}
+#[cfg(feature = "full")]
+pub fn fold_local<F>(f: &mut F, node: Local) -> Local
+where
+ F: Fold + ?Sized,
+{
+ Local {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ let_token: Token![let](tokens_helper(f, &node.let_token.span)),
+ pat: f.fold_pat(node.pat),
+ init: (node.init).map(|it| {
+ (
+ Token ! [ = ](tokens_helper(f, &(it).0.spans)),
+ Box::new(f.fold_expr(*(it).1)),
+ )
+ }),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_macro<F>(f: &mut F, node: Macro) -> Macro
+where
+ F: Fold + ?Sized,
+{
+ Macro {
+ path: f.fold_path(node.path),
+ bang_token: Token![!](tokens_helper(f, &node.bang_token.spans)),
+ delimiter: f.fold_macro_delimiter(node.delimiter),
+ tokens: node.tokens,
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_macro_delimiter<F>(f: &mut F, node: MacroDelimiter) -> MacroDelimiter
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ MacroDelimiter::Paren(_binding_0) => {
+ MacroDelimiter::Paren(Paren(tokens_helper(f, &_binding_0.span)))
+ }
+ MacroDelimiter::Brace(_binding_0) => {
+ MacroDelimiter::Brace(Brace(tokens_helper(f, &_binding_0.span)))
+ }
+ MacroDelimiter::Bracket(_binding_0) => {
+ MacroDelimiter::Bracket(Bracket(tokens_helper(f, &_binding_0.span)))
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_member<F>(f: &mut F, node: Member) -> Member
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Member::Named(_binding_0) => Member::Named(f.fold_ident(_binding_0)),
+ Member::Unnamed(_binding_0) => Member::Unnamed(f.fold_index(_binding_0)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_meta<F>(f: &mut F, node: Meta) -> Meta
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Meta::Path(_binding_0) => Meta::Path(f.fold_path(_binding_0)),
+ Meta::List(_binding_0) => Meta::List(f.fold_meta_list(_binding_0)),
+ Meta::NameValue(_binding_0) => Meta::NameValue(f.fold_meta_name_value(_binding_0)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_meta_list<F>(f: &mut F, node: MetaList) -> MetaList
+where
+ F: Fold + ?Sized,
+{
+ MetaList {
+ path: f.fold_path(node.path),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ nested: FoldHelper::lift(node.nested, |it| f.fold_nested_meta(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_meta_name_value<F>(f: &mut F, node: MetaNameValue) -> MetaNameValue
+where
+ F: Fold + ?Sized,
+{
+ MetaNameValue {
+ path: f.fold_path(node.path),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ lit: f.fold_lit(node.lit),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_method_turbofish<F>(f: &mut F, node: MethodTurbofish) -> MethodTurbofish
+where
+ F: Fold + ?Sized,
+{
+ MethodTurbofish {
+ colon2_token: Token ! [ :: ](tokens_helper(f, &node.colon2_token.spans)),
+ lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)),
+ args: FoldHelper::lift(node.args, |it| f.fold_generic_method_argument(it)),
+ gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_nested_meta<F>(f: &mut F, node: NestedMeta) -> NestedMeta
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ NestedMeta::Meta(_binding_0) => NestedMeta::Meta(f.fold_meta(_binding_0)),
+ NestedMeta::Lit(_binding_0) => NestedMeta::Lit(f.fold_lit(_binding_0)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_parenthesized_generic_arguments<F>(
+ f: &mut F,
+ node: ParenthesizedGenericArguments,
+) -> ParenthesizedGenericArguments
+where
+ F: Fold + ?Sized,
+{
+ ParenthesizedGenericArguments {
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ inputs: FoldHelper::lift(node.inputs, |it| f.fold_type(it)),
+ output: f.fold_return_type(node.output),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat<F>(f: &mut F, node: Pat) -> Pat
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Pat::Box(_binding_0) => Pat::Box(f.fold_pat_box(_binding_0)),
+ Pat::Ident(_binding_0) => Pat::Ident(f.fold_pat_ident(_binding_0)),
+ Pat::Lit(_binding_0) => Pat::Lit(f.fold_pat_lit(_binding_0)),
+ Pat::Macro(_binding_0) => Pat::Macro(f.fold_pat_macro(_binding_0)),
+ Pat::Or(_binding_0) => Pat::Or(f.fold_pat_or(_binding_0)),
+ Pat::Path(_binding_0) => Pat::Path(f.fold_pat_path(_binding_0)),
+ Pat::Range(_binding_0) => Pat::Range(f.fold_pat_range(_binding_0)),
+ Pat::Reference(_binding_0) => Pat::Reference(f.fold_pat_reference(_binding_0)),
+ Pat::Rest(_binding_0) => Pat::Rest(f.fold_pat_rest(_binding_0)),
+ Pat::Slice(_binding_0) => Pat::Slice(f.fold_pat_slice(_binding_0)),
+ Pat::Struct(_binding_0) => Pat::Struct(f.fold_pat_struct(_binding_0)),
+ Pat::Tuple(_binding_0) => Pat::Tuple(f.fold_pat_tuple(_binding_0)),
+ Pat::TupleStruct(_binding_0) => Pat::TupleStruct(f.fold_pat_tuple_struct(_binding_0)),
+ Pat::Type(_binding_0) => Pat::Type(f.fold_pat_type(_binding_0)),
+ Pat::Verbatim(_binding_0) => Pat::Verbatim(_binding_0),
+ Pat::Wild(_binding_0) => Pat::Wild(f.fold_pat_wild(_binding_0)),
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_box<F>(f: &mut F, node: PatBox) -> PatBox
+where
+ F: Fold + ?Sized,
+{
+ PatBox {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ box_token: Token![box](tokens_helper(f, &node.box_token.span)),
+ pat: Box::new(f.fold_pat(*node.pat)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_ident<F>(f: &mut F, node: PatIdent) -> PatIdent
+where
+ F: Fold + ?Sized,
+{
+ PatIdent {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ by_ref: (node.by_ref).map(|it| Token![ref](tokens_helper(f, &it.span))),
+ mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+ ident: f.fold_ident(node.ident),
+ subpat: (node.subpat).map(|it| {
+ (
+ Token ! [ @ ](tokens_helper(f, &(it).0.spans)),
+ Box::new(f.fold_pat(*(it).1)),
+ )
+ }),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_lit<F>(f: &mut F, node: PatLit) -> PatLit
+where
+ F: Fold + ?Sized,
+{
+ PatLit {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ expr: Box::new(f.fold_expr(*node.expr)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_macro<F>(f: &mut F, node: PatMacro) -> PatMacro
+where
+ F: Fold + ?Sized,
+{
+ PatMacro {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ mac: f.fold_macro(node.mac),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_or<F>(f: &mut F, node: PatOr) -> PatOr
+where
+ F: Fold + ?Sized,
+{
+ PatOr {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ leading_vert: (node.leading_vert).map(|it| Token ! [ | ](tokens_helper(f, &it.spans))),
+ cases: FoldHelper::lift(node.cases, |it| f.fold_pat(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_path<F>(f: &mut F, node: PatPath) -> PatPath
+where
+ F: Fold + ?Sized,
+{
+ PatPath {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ qself: (node.qself).map(|it| f.fold_qself(it)),
+ path: f.fold_path(node.path),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_range<F>(f: &mut F, node: PatRange) -> PatRange
+where
+ F: Fold + ?Sized,
+{
+ PatRange {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ lo: Box::new(f.fold_expr(*node.lo)),
+ limits: f.fold_range_limits(node.limits),
+ hi: Box::new(f.fold_expr(*node.hi)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_reference<F>(f: &mut F, node: PatReference) -> PatReference
+where
+ F: Fold + ?Sized,
+{
+ PatReference {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)),
+ mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+ pat: Box::new(f.fold_pat(*node.pat)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_rest<F>(f: &mut F, node: PatRest) -> PatRest
+where
+ F: Fold + ?Sized,
+{
+ PatRest {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ dot2_token: Token![..](tokens_helper(f, &node.dot2_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_slice<F>(f: &mut F, node: PatSlice) -> PatSlice
+where
+ F: Fold + ?Sized,
+{
+ PatSlice {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)),
+ elems: FoldHelper::lift(node.elems, |it| f.fold_pat(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_struct<F>(f: &mut F, node: PatStruct) -> PatStruct
+where
+ F: Fold + ?Sized,
+{
+ PatStruct {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ path: f.fold_path(node.path),
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ fields: FoldHelper::lift(node.fields, |it| f.fold_field_pat(it)),
+ dot2_token: (node.dot2_token).map(|it| Token![..](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_tuple<F>(f: &mut F, node: PatTuple) -> PatTuple
+where
+ F: Fold + ?Sized,
+{
+ PatTuple {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ elems: FoldHelper::lift(node.elems, |it| f.fold_pat(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_tuple_struct<F>(f: &mut F, node: PatTupleStruct) -> PatTupleStruct
+where
+ F: Fold + ?Sized,
+{
+ PatTupleStruct {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ path: f.fold_path(node.path),
+ pat: f.fold_pat_tuple(node.pat),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_type<F>(f: &mut F, node: PatType) -> PatType
+where
+ F: Fold + ?Sized,
+{
+ PatType {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ pat: Box::new(f.fold_pat(*node.pat)),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ ty: Box::new(f.fold_type(*node.ty)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_pat_wild<F>(f: &mut F, node: PatWild) -> PatWild
+where
+ F: Fold + ?Sized,
+{
+ PatWild {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ underscore_token: Token![_](tokens_helper(f, &node.underscore_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_path<F>(f: &mut F, node: Path) -> Path
+where
+ F: Fold + ?Sized,
+{
+ Path {
+ leading_colon: (node.leading_colon).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))),
+ segments: FoldHelper::lift(node.segments, |it| f.fold_path_segment(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_path_arguments<F>(f: &mut F, node: PathArguments) -> PathArguments
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ PathArguments::None => PathArguments::None,
+ PathArguments::AngleBracketed(_binding_0) => {
+ PathArguments::AngleBracketed(f.fold_angle_bracketed_generic_arguments(_binding_0))
+ }
+ PathArguments::Parenthesized(_binding_0) => {
+ PathArguments::Parenthesized(f.fold_parenthesized_generic_arguments(_binding_0))
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_path_segment<F>(f: &mut F, node: PathSegment) -> PathSegment
+where
+ F: Fold + ?Sized,
+{
+ PathSegment {
+ ident: f.fold_ident(node.ident),
+ arguments: f.fold_path_arguments(node.arguments),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_predicate_eq<F>(f: &mut F, node: PredicateEq) -> PredicateEq
+where
+ F: Fold + ?Sized,
+{
+ PredicateEq {
+ lhs_ty: f.fold_type(node.lhs_ty),
+ eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)),
+ rhs_ty: f.fold_type(node.rhs_ty),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_predicate_lifetime<F>(f: &mut F, node: PredicateLifetime) -> PredicateLifetime
+where
+ F: Fold + ?Sized,
+{
+ PredicateLifetime {
+ lifetime: f.fold_lifetime(node.lifetime),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_lifetime(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_predicate_type<F>(f: &mut F, node: PredicateType) -> PredicateType
+where
+ F: Fold + ?Sized,
+{
+ PredicateType {
+ lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)),
+ bounded_ty: f.fold_type(node.bounded_ty),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_qself<F>(f: &mut F, node: QSelf) -> QSelf
+where
+ F: Fold + ?Sized,
+{
+ QSelf {
+ lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)),
+ ty: Box::new(f.fold_type(*node.ty)),
+ position: node.position,
+ as_token: (node.as_token).map(|it| Token![as](tokens_helper(f, &it.span))),
+ gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_range_limits<F>(f: &mut F, node: RangeLimits) -> RangeLimits
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ RangeLimits::HalfOpen(_binding_0) => {
+ RangeLimits::HalfOpen(Token![..](tokens_helper(f, &_binding_0.spans)))
+ }
+ RangeLimits::Closed(_binding_0) => {
+ RangeLimits::Closed(Token ! [ ..= ](tokens_helper(f, &_binding_0.spans)))
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_receiver<F>(f: &mut F, node: Receiver) -> Receiver
+where
+ F: Fold + ?Sized,
+{
+ Receiver {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ reference: (node.reference).map(|it| {
+ (
+ Token ! [ & ](tokens_helper(f, &(it).0.spans)),
+ ((it).1).map(|it| f.fold_lifetime(it)),
+ )
+ }),
+ mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+ self_token: Token![self](tokens_helper(f, &node.self_token.span)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_return_type<F>(f: &mut F, node: ReturnType) -> ReturnType
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ ReturnType::Default => ReturnType::Default,
+ ReturnType::Type(_binding_0, _binding_1) => ReturnType::Type(
+ Token ! [ -> ](tokens_helper(f, &_binding_0.spans)),
+ Box::new(f.fold_type(*_binding_1)),
+ ),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_signature<F>(f: &mut F, node: Signature) -> Signature
+where
+ F: Fold + ?Sized,
+{
+ Signature {
+ constness: (node.constness).map(|it| Token![const](tokens_helper(f, &it.span))),
+ asyncness: (node.asyncness).map(|it| Token![async](tokens_helper(f, &it.span))),
+ unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))),
+ abi: (node.abi).map(|it| f.fold_abi(it)),
+ fn_token: Token![fn](tokens_helper(f, &node.fn_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ inputs: FoldHelper::lift(node.inputs, |it| f.fold_fn_arg(it)),
+ variadic: (node.variadic).map(|it| f.fold_variadic(it)),
+ output: f.fold_return_type(node.output),
+ }
+}
+pub fn fold_span<F>(f: &mut F, node: Span) -> Span
+where
+ F: Fold + ?Sized,
+{
+ node
+}
+#[cfg(feature = "full")]
+pub fn fold_stmt<F>(f: &mut F, node: Stmt) -> Stmt
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Stmt::Local(_binding_0) => Stmt::Local(f.fold_local(_binding_0)),
+ Stmt::Item(_binding_0) => Stmt::Item(f.fold_item(_binding_0)),
+ Stmt::Expr(_binding_0) => Stmt::Expr(f.fold_expr(_binding_0)),
+ Stmt::Semi(_binding_0, _binding_1) => Stmt::Semi(
+ f.fold_expr(_binding_0),
+ Token ! [ ; ](tokens_helper(f, &_binding_1.spans)),
+ ),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_trait_bound<F>(f: &mut F, node: TraitBound) -> TraitBound
+where
+ F: Fold + ?Sized,
+{
+ TraitBound {
+ paren_token: (node.paren_token).map(|it| Paren(tokens_helper(f, &it.span))),
+ modifier: f.fold_trait_bound_modifier(node.modifier),
+ lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)),
+ path: f.fold_path(node.path),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_trait_bound_modifier<F>(f: &mut F, node: TraitBoundModifier) -> TraitBoundModifier
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ TraitBoundModifier::None => TraitBoundModifier::None,
+ TraitBoundModifier::Maybe(_binding_0) => {
+ TraitBoundModifier::Maybe(Token ! [ ? ](tokens_helper(f, &_binding_0.spans)))
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item<F>(f: &mut F, node: TraitItem) -> TraitItem
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ TraitItem::Const(_binding_0) => TraitItem::Const(f.fold_trait_item_const(_binding_0)),
+ TraitItem::Method(_binding_0) => TraitItem::Method(f.fold_trait_item_method(_binding_0)),
+ TraitItem::Type(_binding_0) => TraitItem::Type(f.fold_trait_item_type(_binding_0)),
+ TraitItem::Macro(_binding_0) => TraitItem::Macro(f.fold_trait_item_macro(_binding_0)),
+ TraitItem::Verbatim(_binding_0) => TraitItem::Verbatim(_binding_0),
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_const<F>(f: &mut F, node: TraitItemConst) -> TraitItemConst
+where
+ F: Fold + ?Sized,
+{
+ TraitItemConst {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ const_token: Token![const](tokens_helper(f, &node.const_token.span)),
+ ident: f.fold_ident(node.ident),
+ colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)),
+ ty: f.fold_type(node.ty),
+ default: (node.default).map(|it| {
+ (
+ Token ! [ = ](tokens_helper(f, &(it).0.spans)),
+ f.fold_expr((it).1),
+ )
+ }),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_macro<F>(f: &mut F, node: TraitItemMacro) -> TraitItemMacro
+where
+ F: Fold + ?Sized,
+{
+ TraitItemMacro {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ mac: f.fold_macro(node.mac),
+ semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_method<F>(f: &mut F, node: TraitItemMethod) -> TraitItemMethod
+where
+ F: Fold + ?Sized,
+{
+ TraitItemMethod {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ sig: f.fold_signature(node.sig),
+ default: (node.default).map(|it| f.fold_block(it)),
+ semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_type<F>(f: &mut F, node: TraitItemType) -> TraitItemType
+where
+ F: Fold + ?Sized,
+{
+ TraitItemType {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ type_token: Token![type](tokens_helper(f, &node.type_token.span)),
+ ident: f.fold_ident(node.ident),
+ generics: f.fold_generics(node.generics),
+ colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)),
+ default: (node.default).map(|it| {
+ (
+ Token ! [ = ](tokens_helper(f, &(it).0.spans)),
+ f.fold_type((it).1),
+ )
+ }),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type<F>(f: &mut F, node: Type) -> Type
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Type::Array(_binding_0) => Type::Array(f.fold_type_array(_binding_0)),
+ Type::BareFn(_binding_0) => Type::BareFn(f.fold_type_bare_fn(_binding_0)),
+ Type::Group(_binding_0) => Type::Group(f.fold_type_group(_binding_0)),
+ Type::ImplTrait(_binding_0) => Type::ImplTrait(f.fold_type_impl_trait(_binding_0)),
+ Type::Infer(_binding_0) => Type::Infer(f.fold_type_infer(_binding_0)),
+ Type::Macro(_binding_0) => Type::Macro(f.fold_type_macro(_binding_0)),
+ Type::Never(_binding_0) => Type::Never(f.fold_type_never(_binding_0)),
+ Type::Paren(_binding_0) => Type::Paren(f.fold_type_paren(_binding_0)),
+ Type::Path(_binding_0) => Type::Path(f.fold_type_path(_binding_0)),
+ Type::Ptr(_binding_0) => Type::Ptr(f.fold_type_ptr(_binding_0)),
+ Type::Reference(_binding_0) => Type::Reference(f.fold_type_reference(_binding_0)),
+ Type::Slice(_binding_0) => Type::Slice(f.fold_type_slice(_binding_0)),
+ Type::TraitObject(_binding_0) => Type::TraitObject(f.fold_type_trait_object(_binding_0)),
+ Type::Tuple(_binding_0) => Type::Tuple(f.fold_type_tuple(_binding_0)),
+ Type::Verbatim(_binding_0) => Type::Verbatim(_binding_0),
+ _ => unreachable!(),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_array<F>(f: &mut F, node: TypeArray) -> TypeArray
+where
+ F: Fold + ?Sized,
+{
+ TypeArray {
+ bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)),
+ elem: Box::new(f.fold_type(*node.elem)),
+ semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)),
+ len: f.fold_expr(node.len),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_bare_fn<F>(f: &mut F, node: TypeBareFn) -> TypeBareFn
+where
+ F: Fold + ?Sized,
+{
+ TypeBareFn {
+ lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)),
+ unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))),
+ abi: (node.abi).map(|it| f.fold_abi(it)),
+ fn_token: Token![fn](tokens_helper(f, &node.fn_token.span)),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ inputs: FoldHelper::lift(node.inputs, |it| f.fold_bare_fn_arg(it)),
+ variadic: (node.variadic).map(|it| f.fold_variadic(it)),
+ output: f.fold_return_type(node.output),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_group<F>(f: &mut F, node: TypeGroup) -> TypeGroup
+where
+ F: Fold + ?Sized,
+{
+ TypeGroup {
+ group_token: Group(tokens_helper(f, &node.group_token.span)),
+ elem: Box::new(f.fold_type(*node.elem)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_impl_trait<F>(f: &mut F, node: TypeImplTrait) -> TypeImplTrait
+where
+ F: Fold + ?Sized,
+{
+ TypeImplTrait {
+ impl_token: Token![impl](tokens_helper(f, &node.impl_token.span)),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_infer<F>(f: &mut F, node: TypeInfer) -> TypeInfer
+where
+ F: Fold + ?Sized,
+{
+ TypeInfer {
+ underscore_token: Token![_](tokens_helper(f, &node.underscore_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_macro<F>(f: &mut F, node: TypeMacro) -> TypeMacro
+where
+ F: Fold + ?Sized,
+{
+ TypeMacro {
+ mac: f.fold_macro(node.mac),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_never<F>(f: &mut F, node: TypeNever) -> TypeNever
+where
+ F: Fold + ?Sized,
+{
+ TypeNever {
+ bang_token: Token![!](tokens_helper(f, &node.bang_token.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_param<F>(f: &mut F, node: TypeParam) -> TypeParam
+where
+ F: Fold + ?Sized,
+{
+ TypeParam {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ ident: f.fold_ident(node.ident),
+ colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)),
+ eq_token: (node.eq_token).map(|it| Token ! [ = ](tokens_helper(f, &it.spans))),
+ default: (node.default).map(|it| f.fold_type(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_param_bound<F>(f: &mut F, node: TypeParamBound) -> TypeParamBound
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ TypeParamBound::Trait(_binding_0) => TypeParamBound::Trait(f.fold_trait_bound(_binding_0)),
+ TypeParamBound::Lifetime(_binding_0) => {
+ TypeParamBound::Lifetime(f.fold_lifetime(_binding_0))
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_paren<F>(f: &mut F, node: TypeParen) -> TypeParen
+where
+ F: Fold + ?Sized,
+{
+ TypeParen {
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ elem: Box::new(f.fold_type(*node.elem)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_path<F>(f: &mut F, node: TypePath) -> TypePath
+where
+ F: Fold + ?Sized,
+{
+ TypePath {
+ qself: (node.qself).map(|it| f.fold_qself(it)),
+ path: f.fold_path(node.path),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_ptr<F>(f: &mut F, node: TypePtr) -> TypePtr
+where
+ F: Fold + ?Sized,
+{
+ TypePtr {
+ star_token: Token ! [ * ](tokens_helper(f, &node.star_token.spans)),
+ const_token: (node.const_token).map(|it| Token![const](tokens_helper(f, &it.span))),
+ mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+ elem: Box::new(f.fold_type(*node.elem)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_reference<F>(f: &mut F, node: TypeReference) -> TypeReference
+where
+ F: Fold + ?Sized,
+{
+ TypeReference {
+ and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)),
+ lifetime: (node.lifetime).map(|it| f.fold_lifetime(it)),
+ mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))),
+ elem: Box::new(f.fold_type(*node.elem)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_slice<F>(f: &mut F, node: TypeSlice) -> TypeSlice
+where
+ F: Fold + ?Sized,
+{
+ TypeSlice {
+ bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)),
+ elem: Box::new(f.fold_type(*node.elem)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_trait_object<F>(f: &mut F, node: TypeTraitObject) -> TypeTraitObject
+where
+ F: Fold + ?Sized,
+{
+ TypeTraitObject {
+ dyn_token: (node.dyn_token).map(|it| Token![dyn](tokens_helper(f, &it.span))),
+ bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_type_tuple<F>(f: &mut F, node: TypeTuple) -> TypeTuple
+where
+ F: Fold + ?Sized,
+{
+ TypeTuple {
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ elems: FoldHelper::lift(node.elems, |it| f.fold_type(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_un_op<F>(f: &mut F, node: UnOp) -> UnOp
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ UnOp::Deref(_binding_0) => UnOp::Deref(Token ! [ * ](tokens_helper(f, &_binding_0.spans))),
+ UnOp::Not(_binding_0) => UnOp::Not(Token![!](tokens_helper(f, &_binding_0.spans))),
+ UnOp::Neg(_binding_0) => UnOp::Neg(Token ! [ - ](tokens_helper(f, &_binding_0.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_glob<F>(f: &mut F, node: UseGlob) -> UseGlob
+where
+ F: Fold + ?Sized,
+{
+ UseGlob {
+ star_token: Token ! [ * ](tokens_helper(f, &node.star_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_group<F>(f: &mut F, node: UseGroup) -> UseGroup
+where
+ F: Fold + ?Sized,
+{
+ UseGroup {
+ brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
+ items: FoldHelper::lift(node.items, |it| f.fold_use_tree(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_name<F>(f: &mut F, node: UseName) -> UseName
+where
+ F: Fold + ?Sized,
+{
+ UseName {
+ ident: f.fold_ident(node.ident),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_path<F>(f: &mut F, node: UsePath) -> UsePath
+where
+ F: Fold + ?Sized,
+{
+ UsePath {
+ ident: f.fold_ident(node.ident),
+ colon2_token: Token ! [ :: ](tokens_helper(f, &node.colon2_token.spans)),
+ tree: Box::new(f.fold_use_tree(*node.tree)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_rename<F>(f: &mut F, node: UseRename) -> UseRename
+where
+ F: Fold + ?Sized,
+{
+ UseRename {
+ ident: f.fold_ident(node.ident),
+ as_token: Token![as](tokens_helper(f, &node.as_token.span)),
+ rename: f.fold_ident(node.rename),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_tree<F>(f: &mut F, node: UseTree) -> UseTree
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ UseTree::Path(_binding_0) => UseTree::Path(f.fold_use_path(_binding_0)),
+ UseTree::Name(_binding_0) => UseTree::Name(f.fold_use_name(_binding_0)),
+ UseTree::Rename(_binding_0) => UseTree::Rename(f.fold_use_rename(_binding_0)),
+ UseTree::Glob(_binding_0) => UseTree::Glob(f.fold_use_glob(_binding_0)),
+ UseTree::Group(_binding_0) => UseTree::Group(f.fold_use_group(_binding_0)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_variadic<F>(f: &mut F, node: Variadic) -> Variadic
+where
+ F: Fold + ?Sized,
+{
+ Variadic {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ dots: Token ! [ ... ](tokens_helper(f, &node.dots.spans)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_variant<F>(f: &mut F, node: Variant) -> Variant
+where
+ F: Fold + ?Sized,
+{
+ Variant {
+ attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)),
+ ident: f.fold_ident(node.ident),
+ fields: f.fold_fields(node.fields),
+ discriminant: (node.discriminant).map(|it| {
+ (
+ Token ! [ = ](tokens_helper(f, &(it).0.spans)),
+ f.fold_expr((it).1),
+ )
+ }),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_vis_crate<F>(f: &mut F, node: VisCrate) -> VisCrate
+where
+ F: Fold + ?Sized,
+{
+ VisCrate {
+ crate_token: Token![crate](tokens_helper(f, &node.crate_token.span)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_vis_public<F>(f: &mut F, node: VisPublic) -> VisPublic
+where
+ F: Fold + ?Sized,
+{
+ VisPublic {
+ pub_token: Token![pub](tokens_helper(f, &node.pub_token.span)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_vis_restricted<F>(f: &mut F, node: VisRestricted) -> VisRestricted
+where
+ F: Fold + ?Sized,
+{
+ VisRestricted {
+ pub_token: Token![pub](tokens_helper(f, &node.pub_token.span)),
+ paren_token: Paren(tokens_helper(f, &node.paren_token.span)),
+ in_token: (node.in_token).map(|it| Token![in](tokens_helper(f, &it.span))),
+ path: Box::new(f.fold_path(*node.path)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_visibility<F>(f: &mut F, node: Visibility) -> Visibility
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ Visibility::Public(_binding_0) => Visibility::Public(f.fold_vis_public(_binding_0)),
+ Visibility::Crate(_binding_0) => Visibility::Crate(f.fold_vis_crate(_binding_0)),
+ Visibility::Restricted(_binding_0) => {
+ Visibility::Restricted(f.fold_vis_restricted(_binding_0))
+ }
+ Visibility::Inherited => Visibility::Inherited,
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_where_clause<F>(f: &mut F, node: WhereClause) -> WhereClause
+where
+ F: Fold + ?Sized,
+{
+ WhereClause {
+ where_token: Token![where](tokens_helper(f, &node.where_token.span)),
+ predicates: FoldHelper::lift(node.predicates, |it| f.fold_where_predicate(it)),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn fold_where_predicate<F>(f: &mut F, node: WherePredicate) -> WherePredicate
+where
+ F: Fold + ?Sized,
+{
+ match node {
+ WherePredicate::Type(_binding_0) => WherePredicate::Type(f.fold_predicate_type(_binding_0)),
+ WherePredicate::Lifetime(_binding_0) => {
+ WherePredicate::Lifetime(f.fold_predicate_lifetime(_binding_0))
+ }
+ WherePredicate::Eq(_binding_0) => WherePredicate::Eq(f.fold_predicate_eq(_binding_0)),
+ }
+}
diff --git a/syn/src/gen/visit.rs b/syn/src/gen/visit.rs
new file mode 100644
index 0000000..b667f53
--- /dev/null
+++ b/syn/src/gen/visit.rs
@@ -0,0 +1,3792 @@
+// This file is @generated by syn-internal-codegen.
+// It is not intended for manual editing.
+
+#![allow(unused_variables)]
+#[cfg(any(feature = "full", feature = "derive"))]
+use crate::gen::helper::visit::*;
+#[cfg(any(feature = "full", feature = "derive"))]
+use crate::punctuated::Punctuated;
+use crate::*;
+use proc_macro2::Span;
+#[cfg(feature = "full")]
+macro_rules! full {
+ ($e:expr) => {
+ $e
+ };
+}
+#[cfg(all(feature = "derive", not(feature = "full")))]
+macro_rules! full {
+ ($e:expr) => {
+ unreachable!()
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! skip {
+ ($($tt:tt)*) => {};
+}
+/// Syntax tree traversal to walk a shared borrow of a syntax tree.
+///
+/// See the [module documentation] for details.
+///
+/// [module documentation]: self
+///
+/// *This trait is available if Syn is built with the `"visit"` feature.*
+pub trait Visit<'ast> {
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_abi(&mut self, i: &'ast Abi) {
+ visit_abi(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_angle_bracketed_generic_arguments(&mut self, i: &'ast AngleBracketedGenericArguments) {
+ visit_angle_bracketed_generic_arguments(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_arm(&mut self, i: &'ast Arm) {
+ visit_arm(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_attr_style(&mut self, i: &'ast AttrStyle) {
+ visit_attr_style(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_attribute(&mut self, i: &'ast Attribute) {
+ visit_attribute(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_bare_fn_arg(&mut self, i: &'ast BareFnArg) {
+ visit_bare_fn_arg(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_bin_op(&mut self, i: &'ast BinOp) {
+ visit_bin_op(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_binding(&mut self, i: &'ast Binding) {
+ visit_binding(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_block(&mut self, i: &'ast Block) {
+ visit_block(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_bound_lifetimes(&mut self, i: &'ast BoundLifetimes) {
+ visit_bound_lifetimes(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_const_param(&mut self, i: &'ast ConstParam) {
+ visit_const_param(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_constraint(&mut self, i: &'ast Constraint) {
+ visit_constraint(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data(&mut self, i: &'ast Data) {
+ visit_data(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_enum(&mut self, i: &'ast DataEnum) {
+ visit_data_enum(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_struct(&mut self, i: &'ast DataStruct) {
+ visit_data_struct(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_union(&mut self, i: &'ast DataUnion) {
+ visit_data_union(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_derive_input(&mut self, i: &'ast DeriveInput) {
+ visit_derive_input(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr(&mut self, i: &'ast Expr) {
+ visit_expr(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_array(&mut self, i: &'ast ExprArray) {
+ visit_expr_array(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_assign(&mut self, i: &'ast ExprAssign) {
+ visit_expr_assign(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_assign_op(&mut self, i: &'ast ExprAssignOp) {
+ visit_expr_assign_op(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_async(&mut self, i: &'ast ExprAsync) {
+ visit_expr_async(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_await(&mut self, i: &'ast ExprAwait) {
+ visit_expr_await(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_binary(&mut self, i: &'ast ExprBinary) {
+ visit_expr_binary(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_block(&mut self, i: &'ast ExprBlock) {
+ visit_expr_block(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_box(&mut self, i: &'ast ExprBox) {
+ visit_expr_box(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_break(&mut self, i: &'ast ExprBreak) {
+ visit_expr_break(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_call(&mut self, i: &'ast ExprCall) {
+ visit_expr_call(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_cast(&mut self, i: &'ast ExprCast) {
+ visit_expr_cast(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_closure(&mut self, i: &'ast ExprClosure) {
+ visit_expr_closure(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_continue(&mut self, i: &'ast ExprContinue) {
+ visit_expr_continue(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_field(&mut self, i: &'ast ExprField) {
+ visit_expr_field(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_for_loop(&mut self, i: &'ast ExprForLoop) {
+ visit_expr_for_loop(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_group(&mut self, i: &'ast ExprGroup) {
+ visit_expr_group(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_if(&mut self, i: &'ast ExprIf) {
+ visit_expr_if(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_index(&mut self, i: &'ast ExprIndex) {
+ visit_expr_index(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_let(&mut self, i: &'ast ExprLet) {
+ visit_expr_let(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_lit(&mut self, i: &'ast ExprLit) {
+ visit_expr_lit(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_loop(&mut self, i: &'ast ExprLoop) {
+ visit_expr_loop(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_macro(&mut self, i: &'ast ExprMacro) {
+ visit_expr_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_match(&mut self, i: &'ast ExprMatch) {
+ visit_expr_match(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_method_call(&mut self, i: &'ast ExprMethodCall) {
+ visit_expr_method_call(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_paren(&mut self, i: &'ast ExprParen) {
+ visit_expr_paren(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_path(&mut self, i: &'ast ExprPath) {
+ visit_expr_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_range(&mut self, i: &'ast ExprRange) {
+ visit_expr_range(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_reference(&mut self, i: &'ast ExprReference) {
+ visit_expr_reference(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_repeat(&mut self, i: &'ast ExprRepeat) {
+ visit_expr_repeat(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_return(&mut self, i: &'ast ExprReturn) {
+ visit_expr_return(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_struct(&mut self, i: &'ast ExprStruct) {
+ visit_expr_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_try(&mut self, i: &'ast ExprTry) {
+ visit_expr_try(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_try_block(&mut self, i: &'ast ExprTryBlock) {
+ visit_expr_try_block(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_tuple(&mut self, i: &'ast ExprTuple) {
+ visit_expr_tuple(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_type(&mut self, i: &'ast ExprType) {
+ visit_expr_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_unary(&mut self, i: &'ast ExprUnary) {
+ visit_expr_unary(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_unsafe(&mut self, i: &'ast ExprUnsafe) {
+ visit_expr_unsafe(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_while(&mut self, i: &'ast ExprWhile) {
+ visit_expr_while(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_yield(&mut self, i: &'ast ExprYield) {
+ visit_expr_yield(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_field(&mut self, i: &'ast Field) {
+ visit_field(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_field_pat(&mut self, i: &'ast FieldPat) {
+ visit_field_pat(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_field_value(&mut self, i: &'ast FieldValue) {
+ visit_field_value(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_fields(&mut self, i: &'ast Fields) {
+ visit_fields(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_fields_named(&mut self, i: &'ast FieldsNamed) {
+ visit_fields_named(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_fields_unnamed(&mut self, i: &'ast FieldsUnnamed) {
+ visit_fields_unnamed(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_file(&mut self, i: &'ast File) {
+ visit_file(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_fn_arg(&mut self, i: &'ast FnArg) {
+ visit_fn_arg(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item(&mut self, i: &'ast ForeignItem) {
+ visit_foreign_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_fn(&mut self, i: &'ast ForeignItemFn) {
+ visit_foreign_item_fn(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_macro(&mut self, i: &'ast ForeignItemMacro) {
+ visit_foreign_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_static(&mut self, i: &'ast ForeignItemStatic) {
+ visit_foreign_item_static(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_type(&mut self, i: &'ast ForeignItemType) {
+ visit_foreign_item_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_generic_argument(&mut self, i: &'ast GenericArgument) {
+ visit_generic_argument(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_generic_method_argument(&mut self, i: &'ast GenericMethodArgument) {
+ visit_generic_method_argument(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_generic_param(&mut self, i: &'ast GenericParam) {
+ visit_generic_param(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_generics(&mut self, i: &'ast Generics) {
+ visit_generics(self, i)
+ }
+ fn visit_ident(&mut self, i: &'ast Ident) {
+ visit_ident(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item(&mut self, i: &'ast ImplItem) {
+ visit_impl_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_const(&mut self, i: &'ast ImplItemConst) {
+ visit_impl_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_macro(&mut self, i: &'ast ImplItemMacro) {
+ visit_impl_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_method(&mut self, i: &'ast ImplItemMethod) {
+ visit_impl_item_method(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_type(&mut self, i: &'ast ImplItemType) {
+ visit_impl_item_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_index(&mut self, i: &'ast Index) {
+ visit_index(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item(&mut self, i: &'ast Item) {
+ visit_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_const(&mut self, i: &'ast ItemConst) {
+ visit_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_enum(&mut self, i: &'ast ItemEnum) {
+ visit_item_enum(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_extern_crate(&mut self, i: &'ast ItemExternCrate) {
+ visit_item_extern_crate(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_fn(&mut self, i: &'ast ItemFn) {
+ visit_item_fn(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_foreign_mod(&mut self, i: &'ast ItemForeignMod) {
+ visit_item_foreign_mod(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_impl(&mut self, i: &'ast ItemImpl) {
+ visit_item_impl(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_macro(&mut self, i: &'ast ItemMacro) {
+ visit_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_macro2(&mut self, i: &'ast ItemMacro2) {
+ visit_item_macro2(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_mod(&mut self, i: &'ast ItemMod) {
+ visit_item_mod(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_static(&mut self, i: &'ast ItemStatic) {
+ visit_item_static(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_struct(&mut self, i: &'ast ItemStruct) {
+ visit_item_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_trait(&mut self, i: &'ast ItemTrait) {
+ visit_item_trait(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_trait_alias(&mut self, i: &'ast ItemTraitAlias) {
+ visit_item_trait_alias(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_type(&mut self, i: &'ast ItemType) {
+ visit_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_union(&mut self, i: &'ast ItemUnion) {
+ visit_item_union(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_use(&mut self, i: &'ast ItemUse) {
+ visit_item_use(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_label(&mut self, i: &'ast Label) {
+ visit_label(self, i)
+ }
+ fn visit_lifetime(&mut self, i: &'ast Lifetime) {
+ visit_lifetime(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lifetime_def(&mut self, i: &'ast LifetimeDef) {
+ visit_lifetime_def(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit(&mut self, i: &'ast Lit) {
+ visit_lit(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_bool(&mut self, i: &'ast LitBool) {
+ visit_lit_bool(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_byte(&mut self, i: &'ast LitByte) {
+ visit_lit_byte(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_byte_str(&mut self, i: &'ast LitByteStr) {
+ visit_lit_byte_str(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_char(&mut self, i: &'ast LitChar) {
+ visit_lit_char(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_float(&mut self, i: &'ast LitFloat) {
+ visit_lit_float(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_int(&mut self, i: &'ast LitInt) {
+ visit_lit_int(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_str(&mut self, i: &'ast LitStr) {
+ visit_lit_str(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_local(&mut self, i: &'ast Local) {
+ visit_local(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_macro(&mut self, i: &'ast Macro) {
+ visit_macro(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_macro_delimiter(&mut self, i: &'ast MacroDelimiter) {
+ visit_macro_delimiter(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_member(&mut self, i: &'ast Member) {
+ visit_member(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_meta(&mut self, i: &'ast Meta) {
+ visit_meta(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_meta_list(&mut self, i: &'ast MetaList) {
+ visit_meta_list(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_meta_name_value(&mut self, i: &'ast MetaNameValue) {
+ visit_meta_name_value(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_method_turbofish(&mut self, i: &'ast MethodTurbofish) {
+ visit_method_turbofish(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_nested_meta(&mut self, i: &'ast NestedMeta) {
+ visit_nested_meta(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_parenthesized_generic_arguments(&mut self, i: &'ast ParenthesizedGenericArguments) {
+ visit_parenthesized_generic_arguments(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat(&mut self, i: &'ast Pat) {
+ visit_pat(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_box(&mut self, i: &'ast PatBox) {
+ visit_pat_box(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_ident(&mut self, i: &'ast PatIdent) {
+ visit_pat_ident(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_lit(&mut self, i: &'ast PatLit) {
+ visit_pat_lit(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_macro(&mut self, i: &'ast PatMacro) {
+ visit_pat_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_or(&mut self, i: &'ast PatOr) {
+ visit_pat_or(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_path(&mut self, i: &'ast PatPath) {
+ visit_pat_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_range(&mut self, i: &'ast PatRange) {
+ visit_pat_range(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_reference(&mut self, i: &'ast PatReference) {
+ visit_pat_reference(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_rest(&mut self, i: &'ast PatRest) {
+ visit_pat_rest(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_slice(&mut self, i: &'ast PatSlice) {
+ visit_pat_slice(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_struct(&mut self, i: &'ast PatStruct) {
+ visit_pat_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_tuple(&mut self, i: &'ast PatTuple) {
+ visit_pat_tuple(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_tuple_struct(&mut self, i: &'ast PatTupleStruct) {
+ visit_pat_tuple_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_type(&mut self, i: &'ast PatType) {
+ visit_pat_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_wild(&mut self, i: &'ast PatWild) {
+ visit_pat_wild(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_path(&mut self, i: &'ast Path) {
+ visit_path(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_path_arguments(&mut self, i: &'ast PathArguments) {
+ visit_path_arguments(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_path_segment(&mut self, i: &'ast PathSegment) {
+ visit_path_segment(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_predicate_eq(&mut self, i: &'ast PredicateEq) {
+ visit_predicate_eq(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_predicate_lifetime(&mut self, i: &'ast PredicateLifetime) {
+ visit_predicate_lifetime(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_predicate_type(&mut self, i: &'ast PredicateType) {
+ visit_predicate_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_qself(&mut self, i: &'ast QSelf) {
+ visit_qself(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_range_limits(&mut self, i: &'ast RangeLimits) {
+ visit_range_limits(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_receiver(&mut self, i: &'ast Receiver) {
+ visit_receiver(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_return_type(&mut self, i: &'ast ReturnType) {
+ visit_return_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_signature(&mut self, i: &'ast Signature) {
+ visit_signature(self, i)
+ }
+ fn visit_span(&mut self, i: &Span) {
+ visit_span(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_stmt(&mut self, i: &'ast Stmt) {
+ visit_stmt(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_trait_bound(&mut self, i: &'ast TraitBound) {
+ visit_trait_bound(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_trait_bound_modifier(&mut self, i: &'ast TraitBoundModifier) {
+ visit_trait_bound_modifier(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item(&mut self, i: &'ast TraitItem) {
+ visit_trait_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_const(&mut self, i: &'ast TraitItemConst) {
+ visit_trait_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_macro(&mut self, i: &'ast TraitItemMacro) {
+ visit_trait_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_method(&mut self, i: &'ast TraitItemMethod) {
+ visit_trait_item_method(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_type(&mut self, i: &'ast TraitItemType) {
+ visit_trait_item_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type(&mut self, i: &'ast Type) {
+ visit_type(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_array(&mut self, i: &'ast TypeArray) {
+ visit_type_array(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_bare_fn(&mut self, i: &'ast TypeBareFn) {
+ visit_type_bare_fn(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_group(&mut self, i: &'ast TypeGroup) {
+ visit_type_group(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_impl_trait(&mut self, i: &'ast TypeImplTrait) {
+ visit_type_impl_trait(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_infer(&mut self, i: &'ast TypeInfer) {
+ visit_type_infer(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_macro(&mut self, i: &'ast TypeMacro) {
+ visit_type_macro(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_never(&mut self, i: &'ast TypeNever) {
+ visit_type_never(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_param(&mut self, i: &'ast TypeParam) {
+ visit_type_param(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_param_bound(&mut self, i: &'ast TypeParamBound) {
+ visit_type_param_bound(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_paren(&mut self, i: &'ast TypeParen) {
+ visit_type_paren(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_path(&mut self, i: &'ast TypePath) {
+ visit_type_path(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_ptr(&mut self, i: &'ast TypePtr) {
+ visit_type_ptr(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_reference(&mut self, i: &'ast TypeReference) {
+ visit_type_reference(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_slice(&mut self, i: &'ast TypeSlice) {
+ visit_type_slice(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_trait_object(&mut self, i: &'ast TypeTraitObject) {
+ visit_type_trait_object(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_tuple(&mut self, i: &'ast TypeTuple) {
+ visit_type_tuple(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_un_op(&mut self, i: &'ast UnOp) {
+ visit_un_op(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_glob(&mut self, i: &'ast UseGlob) {
+ visit_use_glob(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_group(&mut self, i: &'ast UseGroup) {
+ visit_use_group(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_name(&mut self, i: &'ast UseName) {
+ visit_use_name(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_path(&mut self, i: &'ast UsePath) {
+ visit_use_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_rename(&mut self, i: &'ast UseRename) {
+ visit_use_rename(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_tree(&mut self, i: &'ast UseTree) {
+ visit_use_tree(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_variadic(&mut self, i: &'ast Variadic) {
+ visit_variadic(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_variant(&mut self, i: &'ast Variant) {
+ visit_variant(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_vis_crate(&mut self, i: &'ast VisCrate) {
+ visit_vis_crate(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_vis_public(&mut self, i: &'ast VisPublic) {
+ visit_vis_public(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_vis_restricted(&mut self, i: &'ast VisRestricted) {
+ visit_vis_restricted(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_visibility(&mut self, i: &'ast Visibility) {
+ visit_visibility(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_where_clause(&mut self, i: &'ast WhereClause) {
+ visit_where_clause(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_where_predicate(&mut self, i: &'ast WherePredicate) {
+ visit_where_predicate(self, i)
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_abi<'ast, V>(v: &mut V, node: &'ast Abi)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.extern_token.span);
+ if let Some(it) = &node.name {
+ v.visit_lit_str(it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_angle_bracketed_generic_arguments<'ast, V>(
+ v: &mut V,
+ node: &'ast AngleBracketedGenericArguments,
+) where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.colon2_token {
+ tokens_helper(v, &it.spans)
+ };
+ tokens_helper(v, &node.lt_token.spans);
+ for el in Punctuated::pairs(&node.args) {
+ let (it, p) = el.into_tuple();
+ v.visit_generic_argument(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ tokens_helper(v, &node.gt_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_arm<'ast, V>(v: &mut V, node: &'ast Arm)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_pat(&node.pat);
+ if let Some(it) = &node.guard {
+ tokens_helper(v, &(it).0.span);
+ v.visit_expr(&*(it).1);
+ };
+ tokens_helper(v, &node.fat_arrow_token.spans);
+ v.visit_expr(&*node.body);
+ if let Some(it) = &node.comma {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_attr_style<'ast, V>(v: &mut V, node: &'ast AttrStyle)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ AttrStyle::Outer => {}
+ AttrStyle::Inner(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_attribute<'ast, V>(v: &mut V, node: &'ast Attribute)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.pound_token.spans);
+ v.visit_attr_style(&node.style);
+ tokens_helper(v, &node.bracket_token.span);
+ v.visit_path(&node.path);
+ skip!(node.tokens);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_bare_fn_arg<'ast, V>(v: &mut V, node: &'ast BareFnArg)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.name {
+ v.visit_ident(&(it).0);
+ tokens_helper(v, &(it).1.spans);
+ };
+ v.visit_type(&node.ty);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_bin_op<'ast, V>(v: &mut V, node: &'ast BinOp)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ BinOp::Add(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Sub(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Mul(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Div(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Rem(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::And(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Or(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::BitXor(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::BitAnd(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::BitOr(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Shl(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Shr(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Eq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Lt(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Le(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Ne(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Ge(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::Gt(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::AddEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::SubEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::MulEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::DivEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::RemEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::BitXorEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::BitAndEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::BitOrEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::ShlEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ BinOp::ShrEq(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_binding<'ast, V>(v: &mut V, node: &'ast Binding)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_type(&node.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_block<'ast, V>(v: &mut V, node: &'ast Block)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.brace_token.span);
+ for it in &node.stmts {
+ v.visit_stmt(it)
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_bound_lifetimes<'ast, V>(v: &mut V, node: &'ast BoundLifetimes)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.for_token.span);
+ tokens_helper(v, &node.lt_token.spans);
+ for el in Punctuated::pairs(&node.lifetimes) {
+ let (it, p) = el.into_tuple();
+ v.visit_lifetime_def(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ tokens_helper(v, &node.gt_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_const_param<'ast, V>(v: &mut V, node: &'ast ConstParam)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.const_token.span);
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.colon_token.spans);
+ v.visit_type(&node.ty);
+ if let Some(it) = &node.eq_token {
+ tokens_helper(v, &it.spans)
+ };
+ if let Some(it) = &node.default {
+ v.visit_expr(it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_constraint<'ast, V>(v: &mut V, node: &'ast Constraint)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.colon_token.spans);
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data<'ast, V>(v: &mut V, node: &'ast Data)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Data::Struct(_binding_0) => {
+ v.visit_data_struct(_binding_0);
+ }
+ Data::Enum(_binding_0) => {
+ v.visit_data_enum(_binding_0);
+ }
+ Data::Union(_binding_0) => {
+ v.visit_data_union(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_enum<'ast, V>(v: &mut V, node: &'ast DataEnum)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.enum_token.span);
+ tokens_helper(v, &node.brace_token.span);
+ for el in Punctuated::pairs(&node.variants) {
+ let (it, p) = el.into_tuple();
+ v.visit_variant(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_struct<'ast, V>(v: &mut V, node: &'ast DataStruct)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.struct_token.span);
+ v.visit_fields(&node.fields);
+ if let Some(it) = &node.semi_token {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_union<'ast, V>(v: &mut V, node: &'ast DataUnion)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.union_token.span);
+ v.visit_fields_named(&node.fields);
+}
+#[cfg(feature = "derive")]
+pub fn visit_derive_input<'ast, V>(v: &mut V, node: &'ast DeriveInput)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ v.visit_data(&node.data);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr<'ast, V>(v: &mut V, node: &'ast Expr)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Expr::Array(_binding_0) => {
+ full!(v.visit_expr_array(_binding_0));
+ }
+ Expr::Assign(_binding_0) => {
+ full!(v.visit_expr_assign(_binding_0));
+ }
+ Expr::AssignOp(_binding_0) => {
+ full!(v.visit_expr_assign_op(_binding_0));
+ }
+ Expr::Async(_binding_0) => {
+ full!(v.visit_expr_async(_binding_0));
+ }
+ Expr::Await(_binding_0) => {
+ full!(v.visit_expr_await(_binding_0));
+ }
+ Expr::Binary(_binding_0) => {
+ v.visit_expr_binary(_binding_0);
+ }
+ Expr::Block(_binding_0) => {
+ full!(v.visit_expr_block(_binding_0));
+ }
+ Expr::Box(_binding_0) => {
+ full!(v.visit_expr_box(_binding_0));
+ }
+ Expr::Break(_binding_0) => {
+ full!(v.visit_expr_break(_binding_0));
+ }
+ Expr::Call(_binding_0) => {
+ v.visit_expr_call(_binding_0);
+ }
+ Expr::Cast(_binding_0) => {
+ v.visit_expr_cast(_binding_0);
+ }
+ Expr::Closure(_binding_0) => {
+ full!(v.visit_expr_closure(_binding_0));
+ }
+ Expr::Continue(_binding_0) => {
+ full!(v.visit_expr_continue(_binding_0));
+ }
+ Expr::Field(_binding_0) => {
+ v.visit_expr_field(_binding_0);
+ }
+ Expr::ForLoop(_binding_0) => {
+ full!(v.visit_expr_for_loop(_binding_0));
+ }
+ Expr::Group(_binding_0) => {
+ full!(v.visit_expr_group(_binding_0));
+ }
+ Expr::If(_binding_0) => {
+ full!(v.visit_expr_if(_binding_0));
+ }
+ Expr::Index(_binding_0) => {
+ v.visit_expr_index(_binding_0);
+ }
+ Expr::Let(_binding_0) => {
+ full!(v.visit_expr_let(_binding_0));
+ }
+ Expr::Lit(_binding_0) => {
+ v.visit_expr_lit(_binding_0);
+ }
+ Expr::Loop(_binding_0) => {
+ full!(v.visit_expr_loop(_binding_0));
+ }
+ Expr::Macro(_binding_0) => {
+ full!(v.visit_expr_macro(_binding_0));
+ }
+ Expr::Match(_binding_0) => {
+ full!(v.visit_expr_match(_binding_0));
+ }
+ Expr::MethodCall(_binding_0) => {
+ full!(v.visit_expr_method_call(_binding_0));
+ }
+ Expr::Paren(_binding_0) => {
+ v.visit_expr_paren(_binding_0);
+ }
+ Expr::Path(_binding_0) => {
+ v.visit_expr_path(_binding_0);
+ }
+ Expr::Range(_binding_0) => {
+ full!(v.visit_expr_range(_binding_0));
+ }
+ Expr::Reference(_binding_0) => {
+ full!(v.visit_expr_reference(_binding_0));
+ }
+ Expr::Repeat(_binding_0) => {
+ full!(v.visit_expr_repeat(_binding_0));
+ }
+ Expr::Return(_binding_0) => {
+ full!(v.visit_expr_return(_binding_0));
+ }
+ Expr::Struct(_binding_0) => {
+ full!(v.visit_expr_struct(_binding_0));
+ }
+ Expr::Try(_binding_0) => {
+ full!(v.visit_expr_try(_binding_0));
+ }
+ Expr::TryBlock(_binding_0) => {
+ full!(v.visit_expr_try_block(_binding_0));
+ }
+ Expr::Tuple(_binding_0) => {
+ full!(v.visit_expr_tuple(_binding_0));
+ }
+ Expr::Type(_binding_0) => {
+ full!(v.visit_expr_type(_binding_0));
+ }
+ Expr::Unary(_binding_0) => {
+ v.visit_expr_unary(_binding_0);
+ }
+ Expr::Unsafe(_binding_0) => {
+ full!(v.visit_expr_unsafe(_binding_0));
+ }
+ Expr::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ Expr::While(_binding_0) => {
+ full!(v.visit_expr_while(_binding_0));
+ }
+ Expr::Yield(_binding_0) => {
+ full!(v.visit_expr_yield(_binding_0));
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_array<'ast, V>(v: &mut V, node: &'ast ExprArray)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.bracket_token.span);
+ for el in Punctuated::pairs(&node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_expr(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_assign<'ast, V>(v: &mut V, node: &'ast ExprAssign)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.left);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_expr(&*node.right);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_assign_op<'ast, V>(v: &mut V, node: &'ast ExprAssignOp)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.left);
+ v.visit_bin_op(&node.op);
+ v.visit_expr(&*node.right);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_async<'ast, V>(v: &mut V, node: &'ast ExprAsync)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.async_token.span);
+ if let Some(it) = &node.capture {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_block(&node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_await<'ast, V>(v: &mut V, node: &'ast ExprAwait)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.base);
+ tokens_helper(v, &node.dot_token.spans);
+ tokens_helper(v, &node.await_token.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.left);
+ v.visit_bin_op(&node.op);
+ v.visit_expr(&*node.right);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_block<'ast, V>(v: &mut V, node: &'ast ExprBlock)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.label {
+ v.visit_label(it)
+ };
+ v.visit_block(&node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_box<'ast, V>(v: &mut V, node: &'ast ExprBox)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.box_token.span);
+ v.visit_expr(&*node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_break<'ast, V>(v: &mut V, node: &'ast ExprBreak)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.break_token.span);
+ if let Some(it) = &node.label {
+ v.visit_lifetime(it)
+ };
+ if let Some(it) = &node.expr {
+ v.visit_expr(&**it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_call<'ast, V>(v: &mut V, node: &'ast ExprCall)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.func);
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.args) {
+ let (it, p) = el.into_tuple();
+ v.visit_expr(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_cast<'ast, V>(v: &mut V, node: &'ast ExprCast)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.expr);
+ tokens_helper(v, &node.as_token.span);
+ v.visit_type(&*node.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_closure<'ast, V>(v: &mut V, node: &'ast ExprClosure)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.asyncness {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.movability {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.capture {
+ tokens_helper(v, &it.span)
+ };
+ tokens_helper(v, &node.or1_token.spans);
+ for el in Punctuated::pairs(&node.inputs) {
+ let (it, p) = el.into_tuple();
+ v.visit_pat(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ tokens_helper(v, &node.or2_token.spans);
+ v.visit_return_type(&node.output);
+ v.visit_expr(&*node.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_continue<'ast, V>(v: &mut V, node: &'ast ExprContinue)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.continue_token.span);
+ if let Some(it) = &node.label {
+ v.visit_lifetime(it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_field<'ast, V>(v: &mut V, node: &'ast ExprField)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.base);
+ tokens_helper(v, &node.dot_token.spans);
+ v.visit_member(&node.member);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_for_loop<'ast, V>(v: &mut V, node: &'ast ExprForLoop)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.label {
+ v.visit_label(it)
+ };
+ tokens_helper(v, &node.for_token.span);
+ v.visit_pat(&node.pat);
+ tokens_helper(v, &node.in_token.span);
+ v.visit_expr(&*node.expr);
+ v.visit_block(&node.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_group<'ast, V>(v: &mut V, node: &'ast ExprGroup)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.group_token.span);
+ v.visit_expr(&*node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_if<'ast, V>(v: &mut V, node: &'ast ExprIf)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.if_token.span);
+ v.visit_expr(&*node.cond);
+ v.visit_block(&node.then_branch);
+ if let Some(it) = &node.else_branch {
+ tokens_helper(v, &(it).0.span);
+ v.visit_expr(&*(it).1);
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_index<'ast, V>(v: &mut V, node: &'ast ExprIndex)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.expr);
+ tokens_helper(v, &node.bracket_token.span);
+ v.visit_expr(&*node.index);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_let<'ast, V>(v: &mut V, node: &'ast ExprLet)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.let_token.span);
+ v.visit_pat(&node.pat);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_expr(&*node.expr);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_lit<'ast, V>(v: &mut V, node: &'ast ExprLit)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_lit(&node.lit);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_loop<'ast, V>(v: &mut V, node: &'ast ExprLoop)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.label {
+ v.visit_label(it)
+ };
+ tokens_helper(v, &node.loop_token.span);
+ v.visit_block(&node.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_macro<'ast, V>(v: &mut V, node: &'ast ExprMacro)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_macro(&node.mac);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_match<'ast, V>(v: &mut V, node: &'ast ExprMatch)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.match_token.span);
+ v.visit_expr(&*node.expr);
+ tokens_helper(v, &node.brace_token.span);
+ for it in &node.arms {
+ v.visit_arm(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_method_call<'ast, V>(v: &mut V, node: &'ast ExprMethodCall)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.receiver);
+ tokens_helper(v, &node.dot_token.spans);
+ v.visit_ident(&node.method);
+ if let Some(it) = &node.turbofish {
+ v.visit_method_turbofish(it)
+ };
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.args) {
+ let (it, p) = el.into_tuple();
+ v.visit_expr(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_paren<'ast, V>(v: &mut V, node: &'ast ExprParen)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.paren_token.span);
+ v.visit_expr(&*node.expr);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_path<'ast, V>(v: &mut V, node: &'ast ExprPath)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.qself {
+ v.visit_qself(it)
+ };
+ v.visit_path(&node.path);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_range<'ast, V>(v: &mut V, node: &'ast ExprRange)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.from {
+ v.visit_expr(&**it)
+ };
+ v.visit_range_limits(&node.limits);
+ if let Some(it) = &node.to {
+ v.visit_expr(&**it)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_reference<'ast, V>(v: &mut V, node: &'ast ExprReference)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.and_token.spans);
+ if let Some(it) = &node.mutability {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_expr(&*node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_repeat<'ast, V>(v: &mut V, node: &'ast ExprRepeat)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.bracket_token.span);
+ v.visit_expr(&*node.expr);
+ tokens_helper(v, &node.semi_token.spans);
+ v.visit_expr(&*node.len);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_return<'ast, V>(v: &mut V, node: &'ast ExprReturn)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.return_token.span);
+ if let Some(it) = &node.expr {
+ v.visit_expr(&**it)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_struct<'ast, V>(v: &mut V, node: &'ast ExprStruct)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_path(&node.path);
+ tokens_helper(v, &node.brace_token.span);
+ for el in Punctuated::pairs(&node.fields) {
+ let (it, p) = el.into_tuple();
+ v.visit_field_value(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ if let Some(it) = &node.dot2_token {
+ tokens_helper(v, &it.spans)
+ };
+ if let Some(it) = &node.rest {
+ v.visit_expr(&**it)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_try<'ast, V>(v: &mut V, node: &'ast ExprTry)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.expr);
+ tokens_helper(v, &node.question_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_try_block<'ast, V>(v: &mut V, node: &'ast ExprTryBlock)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.try_token.span);
+ v.visit_block(&node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_tuple<'ast, V>(v: &mut V, node: &'ast ExprTuple)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_expr(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_type<'ast, V>(v: &mut V, node: &'ast ExprType)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.expr);
+ tokens_helper(v, &node.colon_token.spans);
+ v.visit_type(&*node.ty);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_unary<'ast, V>(v: &mut V, node: &'ast ExprUnary)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_un_op(&node.op);
+ v.visit_expr(&*node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_unsafe<'ast, V>(v: &mut V, node: &'ast ExprUnsafe)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.unsafe_token.span);
+ v.visit_block(&node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_while<'ast, V>(v: &mut V, node: &'ast ExprWhile)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.label {
+ v.visit_label(it)
+ };
+ tokens_helper(v, &node.while_token.span);
+ v.visit_expr(&*node.cond);
+ v.visit_block(&node.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_yield<'ast, V>(v: &mut V, node: &'ast ExprYield)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.yield_token.span);
+ if let Some(it) = &node.expr {
+ v.visit_expr(&**it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_field<'ast, V>(v: &mut V, node: &'ast Field)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ if let Some(it) = &node.ident {
+ v.visit_ident(it)
+ };
+ if let Some(it) = &node.colon_token {
+ tokens_helper(v, &it.spans)
+ };
+ v.visit_type(&node.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_field_pat<'ast, V>(v: &mut V, node: &'ast FieldPat)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_member(&node.member);
+ if let Some(it) = &node.colon_token {
+ tokens_helper(v, &it.spans)
+ };
+ v.visit_pat(&*node.pat);
+}
+#[cfg(feature = "full")]
+pub fn visit_field_value<'ast, V>(v: &mut V, node: &'ast FieldValue)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_member(&node.member);
+ if let Some(it) = &node.colon_token {
+ tokens_helper(v, &it.spans)
+ };
+ v.visit_expr(&node.expr);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_fields<'ast, V>(v: &mut V, node: &'ast Fields)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Fields::Named(_binding_0) => {
+ v.visit_fields_named(_binding_0);
+ }
+ Fields::Unnamed(_binding_0) => {
+ v.visit_fields_unnamed(_binding_0);
+ }
+ Fields::Unit => {}
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_fields_named<'ast, V>(v: &mut V, node: &'ast FieldsNamed)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.brace_token.span);
+ for el in Punctuated::pairs(&node.named) {
+ let (it, p) = el.into_tuple();
+ v.visit_field(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_fields_unnamed<'ast, V>(v: &mut V, node: &'ast FieldsUnnamed)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.unnamed) {
+ let (it, p) = el.into_tuple();
+ v.visit_field(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_file<'ast, V>(v: &mut V, node: &'ast File)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ skip!(node.shebang);
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ for it in &node.items {
+ v.visit_item(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_fn_arg<'ast, V>(v: &mut V, node: &'ast FnArg)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ FnArg::Receiver(_binding_0) => {
+ v.visit_receiver(_binding_0);
+ }
+ FnArg::Typed(_binding_0) => {
+ v.visit_pat_type(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item<'ast, V>(v: &mut V, node: &'ast ForeignItem)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ ForeignItem::Fn(_binding_0) => {
+ v.visit_foreign_item_fn(_binding_0);
+ }
+ ForeignItem::Static(_binding_0) => {
+ v.visit_foreign_item_static(_binding_0);
+ }
+ ForeignItem::Type(_binding_0) => {
+ v.visit_foreign_item_type(_binding_0);
+ }
+ ForeignItem::Macro(_binding_0) => {
+ v.visit_foreign_item_macro(_binding_0);
+ }
+ ForeignItem::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_fn<'ast, V>(v: &mut V, node: &'ast ForeignItemFn)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ v.visit_signature(&node.sig);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_macro<'ast, V>(v: &mut V, node: &'ast ForeignItemMacro)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_macro(&node.mac);
+ if let Some(it) = &node.semi_token {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_static<'ast, V>(v: &mut V, node: &'ast ForeignItemStatic)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.static_token.span);
+ if let Some(it) = &node.mutability {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.colon_token.spans);
+ v.visit_type(&*node.ty);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_type<'ast, V>(v: &mut V, node: &'ast ForeignItemType)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.type_token.span);
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_generic_argument<'ast, V>(v: &mut V, node: &'ast GenericArgument)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ GenericArgument::Lifetime(_binding_0) => {
+ v.visit_lifetime(_binding_0);
+ }
+ GenericArgument::Type(_binding_0) => {
+ v.visit_type(_binding_0);
+ }
+ GenericArgument::Binding(_binding_0) => {
+ v.visit_binding(_binding_0);
+ }
+ GenericArgument::Constraint(_binding_0) => {
+ v.visit_constraint(_binding_0);
+ }
+ GenericArgument::Const(_binding_0) => {
+ v.visit_expr(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_generic_method_argument<'ast, V>(v: &mut V, node: &'ast GenericMethodArgument)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ GenericMethodArgument::Type(_binding_0) => {
+ v.visit_type(_binding_0);
+ }
+ GenericMethodArgument::Const(_binding_0) => {
+ v.visit_expr(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_generic_param<'ast, V>(v: &mut V, node: &'ast GenericParam)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ GenericParam::Type(_binding_0) => {
+ v.visit_type_param(_binding_0);
+ }
+ GenericParam::Lifetime(_binding_0) => {
+ v.visit_lifetime_def(_binding_0);
+ }
+ GenericParam::Const(_binding_0) => {
+ v.visit_const_param(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_generics<'ast, V>(v: &mut V, node: &'ast Generics)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.lt_token {
+ tokens_helper(v, &it.spans)
+ };
+ for el in Punctuated::pairs(&node.params) {
+ let (it, p) = el.into_tuple();
+ v.visit_generic_param(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ if let Some(it) = &node.gt_token {
+ tokens_helper(v, &it.spans)
+ };
+ if let Some(it) = &node.where_clause {
+ v.visit_where_clause(it)
+ };
+}
+pub fn visit_ident<'ast, V>(v: &mut V, node: &'ast Ident)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_span(&node.span());
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item<'ast, V>(v: &mut V, node: &'ast ImplItem)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ ImplItem::Const(_binding_0) => {
+ v.visit_impl_item_const(_binding_0);
+ }
+ ImplItem::Method(_binding_0) => {
+ v.visit_impl_item_method(_binding_0);
+ }
+ ImplItem::Type(_binding_0) => {
+ v.visit_impl_item_type(_binding_0);
+ }
+ ImplItem::Macro(_binding_0) => {
+ v.visit_impl_item_macro(_binding_0);
+ }
+ ImplItem::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_const<'ast, V>(v: &mut V, node: &'ast ImplItemConst)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ if let Some(it) = &node.defaultness {
+ tokens_helper(v, &it.span)
+ };
+ tokens_helper(v, &node.const_token.span);
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.colon_token.spans);
+ v.visit_type(&node.ty);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_expr(&node.expr);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_macro<'ast, V>(v: &mut V, node: &'ast ImplItemMacro)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_macro(&node.mac);
+ if let Some(it) = &node.semi_token {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_method<'ast, V>(v: &mut V, node: &'ast ImplItemMethod)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ if let Some(it) = &node.defaultness {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_signature(&node.sig);
+ v.visit_block(&node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_type<'ast, V>(v: &mut V, node: &'ast ImplItemType)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ if let Some(it) = &node.defaultness {
+ tokens_helper(v, &it.span)
+ };
+ tokens_helper(v, &node.type_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_type(&node.ty);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_index<'ast, V>(v: &mut V, node: &'ast Index)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ skip!(node.index);
+ v.visit_span(&node.span);
+}
+#[cfg(feature = "full")]
+pub fn visit_item<'ast, V>(v: &mut V, node: &'ast Item)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Item::Const(_binding_0) => {
+ v.visit_item_const(_binding_0);
+ }
+ Item::Enum(_binding_0) => {
+ v.visit_item_enum(_binding_0);
+ }
+ Item::ExternCrate(_binding_0) => {
+ v.visit_item_extern_crate(_binding_0);
+ }
+ Item::Fn(_binding_0) => {
+ v.visit_item_fn(_binding_0);
+ }
+ Item::ForeignMod(_binding_0) => {
+ v.visit_item_foreign_mod(_binding_0);
+ }
+ Item::Impl(_binding_0) => {
+ v.visit_item_impl(_binding_0);
+ }
+ Item::Macro(_binding_0) => {
+ v.visit_item_macro(_binding_0);
+ }
+ Item::Macro2(_binding_0) => {
+ v.visit_item_macro2(_binding_0);
+ }
+ Item::Mod(_binding_0) => {
+ v.visit_item_mod(_binding_0);
+ }
+ Item::Static(_binding_0) => {
+ v.visit_item_static(_binding_0);
+ }
+ Item::Struct(_binding_0) => {
+ v.visit_item_struct(_binding_0);
+ }
+ Item::Trait(_binding_0) => {
+ v.visit_item_trait(_binding_0);
+ }
+ Item::TraitAlias(_binding_0) => {
+ v.visit_item_trait_alias(_binding_0);
+ }
+ Item::Type(_binding_0) => {
+ v.visit_item_type(_binding_0);
+ }
+ Item::Union(_binding_0) => {
+ v.visit_item_union(_binding_0);
+ }
+ Item::Use(_binding_0) => {
+ v.visit_item_use(_binding_0);
+ }
+ Item::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_const<'ast, V>(v: &mut V, node: &'ast ItemConst)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.const_token.span);
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.colon_token.spans);
+ v.visit_type(&*node.ty);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_expr(&*node.expr);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_enum<'ast, V>(v: &mut V, node: &'ast ItemEnum)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.enum_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ tokens_helper(v, &node.brace_token.span);
+ for el in Punctuated::pairs(&node.variants) {
+ let (it, p) = el.into_tuple();
+ v.visit_variant(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_extern_crate<'ast, V>(v: &mut V, node: &'ast ItemExternCrate)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.extern_token.span);
+ tokens_helper(v, &node.crate_token.span);
+ v.visit_ident(&node.ident);
+ if let Some(it) = &node.rename {
+ tokens_helper(v, &(it).0.span);
+ v.visit_ident(&(it).1);
+ };
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_fn<'ast, V>(v: &mut V, node: &'ast ItemFn)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ v.visit_signature(&node.sig);
+ v.visit_block(&*node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_foreign_mod<'ast, V>(v: &mut V, node: &'ast ItemForeignMod)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_abi(&node.abi);
+ tokens_helper(v, &node.brace_token.span);
+ for it in &node.items {
+ v.visit_foreign_item(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_impl<'ast, V>(v: &mut V, node: &'ast ItemImpl)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.defaultness {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.unsafety {
+ tokens_helper(v, &it.span)
+ };
+ tokens_helper(v, &node.impl_token.span);
+ v.visit_generics(&node.generics);
+ if let Some(it) = &node.trait_ {
+ if let Some(it) = &(it).0 {
+ tokens_helper(v, &it.spans)
+ };
+ v.visit_path(&(it).1);
+ tokens_helper(v, &(it).2.span);
+ };
+ v.visit_type(&*node.self_ty);
+ tokens_helper(v, &node.brace_token.span);
+ for it in &node.items {
+ v.visit_impl_item(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_macro<'ast, V>(v: &mut V, node: &'ast ItemMacro)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.ident {
+ v.visit_ident(it)
+ };
+ v.visit_macro(&node.mac);
+ if let Some(it) = &node.semi_token {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_macro2<'ast, V>(v: &mut V, node: &'ast ItemMacro2)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.macro_token.span);
+ v.visit_ident(&node.ident);
+ skip!(node.rules);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_mod<'ast, V>(v: &mut V, node: &'ast ItemMod)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.mod_token.span);
+ v.visit_ident(&node.ident);
+ if let Some(it) = &node.content {
+ tokens_helper(v, &(it).0.span);
+ for it in &(it).1 {
+ v.visit_item(it)
+ }
+ };
+ if let Some(it) = &node.semi {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_static<'ast, V>(v: &mut V, node: &'ast ItemStatic)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.static_token.span);
+ if let Some(it) = &node.mutability {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.colon_token.spans);
+ v.visit_type(&*node.ty);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_expr(&*node.expr);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_struct<'ast, V>(v: &mut V, node: &'ast ItemStruct)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.struct_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ v.visit_fields(&node.fields);
+ if let Some(it) = &node.semi_token {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_trait<'ast, V>(v: &mut V, node: &'ast ItemTrait)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ if let Some(it) = &node.unsafety {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.auto_token {
+ tokens_helper(v, &it.span)
+ };
+ tokens_helper(v, &node.trait_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ if let Some(it) = &node.colon_token {
+ tokens_helper(v, &it.spans)
+ };
+ for el in Punctuated::pairs(&node.supertraits) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ tokens_helper(v, &node.brace_token.span);
+ for it in &node.items {
+ v.visit_trait_item(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_trait_alias<'ast, V>(v: &mut V, node: &'ast ItemTraitAlias)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.trait_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ tokens_helper(v, &node.eq_token.spans);
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_type<'ast, V>(v: &mut V, node: &'ast ItemType)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.type_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_type(&*node.ty);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_union<'ast, V>(v: &mut V, node: &'ast ItemUnion)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.union_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ v.visit_fields_named(&node.fields);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_use<'ast, V>(v: &mut V, node: &'ast ItemUse)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_visibility(&node.vis);
+ tokens_helper(v, &node.use_token.span);
+ if let Some(it) = &node.leading_colon {
+ tokens_helper(v, &it.spans)
+ };
+ v.visit_use_tree(&node.tree);
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_label<'ast, V>(v: &mut V, node: &'ast Label)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_lifetime(&node.name);
+ tokens_helper(v, &node.colon_token.spans);
+}
+pub fn visit_lifetime<'ast, V>(v: &mut V, node: &'ast Lifetime)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_span(&node.apostrophe);
+ v.visit_ident(&node.ident);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lifetime_def<'ast, V>(v: &mut V, node: &'ast LifetimeDef)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_lifetime(&node.lifetime);
+ if let Some(it) = &node.colon_token {
+ tokens_helper(v, &it.spans)
+ };
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_lifetime(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit<'ast, V>(v: &mut V, node: &'ast Lit)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Lit::Str(_binding_0) => {
+ v.visit_lit_str(_binding_0);
+ }
+ Lit::ByteStr(_binding_0) => {
+ v.visit_lit_byte_str(_binding_0);
+ }
+ Lit::Byte(_binding_0) => {
+ v.visit_lit_byte(_binding_0);
+ }
+ Lit::Char(_binding_0) => {
+ v.visit_lit_char(_binding_0);
+ }
+ Lit::Int(_binding_0) => {
+ v.visit_lit_int(_binding_0);
+ }
+ Lit::Float(_binding_0) => {
+ v.visit_lit_float(_binding_0);
+ }
+ Lit::Bool(_binding_0) => {
+ v.visit_lit_bool(_binding_0);
+ }
+ Lit::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_bool<'ast, V>(v: &mut V, node: &'ast LitBool)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ skip!(node.value);
+ v.visit_span(&node.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_byte<'ast, V>(v: &mut V, node: &'ast LitByte)
+where
+ V: Visit<'ast> + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_byte_str<'ast, V>(v: &mut V, node: &'ast LitByteStr)
+where
+ V: Visit<'ast> + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_char<'ast, V>(v: &mut V, node: &'ast LitChar)
+where
+ V: Visit<'ast> + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_float<'ast, V>(v: &mut V, node: &'ast LitFloat)
+where
+ V: Visit<'ast> + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_int<'ast, V>(v: &mut V, node: &'ast LitInt)
+where
+ V: Visit<'ast> + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_str<'ast, V>(v: &mut V, node: &'ast LitStr)
+where
+ V: Visit<'ast> + ?Sized,
+{
+}
+#[cfg(feature = "full")]
+pub fn visit_local<'ast, V>(v: &mut V, node: &'ast Local)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.let_token.span);
+ v.visit_pat(&node.pat);
+ if let Some(it) = &node.init {
+ tokens_helper(v, &(it).0.spans);
+ v.visit_expr(&*(it).1);
+ };
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_macro<'ast, V>(v: &mut V, node: &'ast Macro)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_path(&node.path);
+ tokens_helper(v, &node.bang_token.spans);
+ v.visit_macro_delimiter(&node.delimiter);
+ skip!(node.tokens);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_macro_delimiter<'ast, V>(v: &mut V, node: &'ast MacroDelimiter)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ MacroDelimiter::Paren(_binding_0) => {
+ tokens_helper(v, &_binding_0.span);
+ }
+ MacroDelimiter::Brace(_binding_0) => {
+ tokens_helper(v, &_binding_0.span);
+ }
+ MacroDelimiter::Bracket(_binding_0) => {
+ tokens_helper(v, &_binding_0.span);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_member<'ast, V>(v: &mut V, node: &'ast Member)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Member::Named(_binding_0) => {
+ v.visit_ident(_binding_0);
+ }
+ Member::Unnamed(_binding_0) => {
+ v.visit_index(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_meta<'ast, V>(v: &mut V, node: &'ast Meta)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Meta::Path(_binding_0) => {
+ v.visit_path(_binding_0);
+ }
+ Meta::List(_binding_0) => {
+ v.visit_meta_list(_binding_0);
+ }
+ Meta::NameValue(_binding_0) => {
+ v.visit_meta_name_value(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_meta_list<'ast, V>(v: &mut V, node: &'ast MetaList)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_path(&node.path);
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.nested) {
+ let (it, p) = el.into_tuple();
+ v.visit_nested_meta(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_meta_name_value<'ast, V>(v: &mut V, node: &'ast MetaNameValue)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_path(&node.path);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_lit(&node.lit);
+}
+#[cfg(feature = "full")]
+pub fn visit_method_turbofish<'ast, V>(v: &mut V, node: &'ast MethodTurbofish)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.colon2_token.spans);
+ tokens_helper(v, &node.lt_token.spans);
+ for el in Punctuated::pairs(&node.args) {
+ let (it, p) = el.into_tuple();
+ v.visit_generic_method_argument(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ tokens_helper(v, &node.gt_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_nested_meta<'ast, V>(v: &mut V, node: &'ast NestedMeta)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ NestedMeta::Meta(_binding_0) => {
+ v.visit_meta(_binding_0);
+ }
+ NestedMeta::Lit(_binding_0) => {
+ v.visit_lit(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_parenthesized_generic_arguments<'ast, V>(
+ v: &mut V,
+ node: &'ast ParenthesizedGenericArguments,
+) where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.inputs) {
+ let (it, p) = el.into_tuple();
+ v.visit_type(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ v.visit_return_type(&node.output);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat<'ast, V>(v: &mut V, node: &'ast Pat)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Pat::Box(_binding_0) => {
+ v.visit_pat_box(_binding_0);
+ }
+ Pat::Ident(_binding_0) => {
+ v.visit_pat_ident(_binding_0);
+ }
+ Pat::Lit(_binding_0) => {
+ v.visit_pat_lit(_binding_0);
+ }
+ Pat::Macro(_binding_0) => {
+ v.visit_pat_macro(_binding_0);
+ }
+ Pat::Or(_binding_0) => {
+ v.visit_pat_or(_binding_0);
+ }
+ Pat::Path(_binding_0) => {
+ v.visit_pat_path(_binding_0);
+ }
+ Pat::Range(_binding_0) => {
+ v.visit_pat_range(_binding_0);
+ }
+ Pat::Reference(_binding_0) => {
+ v.visit_pat_reference(_binding_0);
+ }
+ Pat::Rest(_binding_0) => {
+ v.visit_pat_rest(_binding_0);
+ }
+ Pat::Slice(_binding_0) => {
+ v.visit_pat_slice(_binding_0);
+ }
+ Pat::Struct(_binding_0) => {
+ v.visit_pat_struct(_binding_0);
+ }
+ Pat::Tuple(_binding_0) => {
+ v.visit_pat_tuple(_binding_0);
+ }
+ Pat::TupleStruct(_binding_0) => {
+ v.visit_pat_tuple_struct(_binding_0);
+ }
+ Pat::Type(_binding_0) => {
+ v.visit_pat_type(_binding_0);
+ }
+ Pat::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ Pat::Wild(_binding_0) => {
+ v.visit_pat_wild(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_box<'ast, V>(v: &mut V, node: &'ast PatBox)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.box_token.span);
+ v.visit_pat(&*node.pat);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_ident<'ast, V>(v: &mut V, node: &'ast PatIdent)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.by_ref {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.mutability {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_ident(&node.ident);
+ if let Some(it) = &node.subpat {
+ tokens_helper(v, &(it).0.spans);
+ v.visit_pat(&*(it).1);
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_lit<'ast, V>(v: &mut V, node: &'ast PatLit)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_macro<'ast, V>(v: &mut V, node: &'ast PatMacro)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_macro(&node.mac);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_or<'ast, V>(v: &mut V, node: &'ast PatOr)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.leading_vert {
+ tokens_helper(v, &it.spans)
+ };
+ for el in Punctuated::pairs(&node.cases) {
+ let (it, p) = el.into_tuple();
+ v.visit_pat(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_path<'ast, V>(v: &mut V, node: &'ast PatPath)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.qself {
+ v.visit_qself(it)
+ };
+ v.visit_path(&node.path);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_range<'ast, V>(v: &mut V, node: &'ast PatRange)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_expr(&*node.lo);
+ v.visit_range_limits(&node.limits);
+ v.visit_expr(&*node.hi);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_reference<'ast, V>(v: &mut V, node: &'ast PatReference)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.and_token.spans);
+ if let Some(it) = &node.mutability {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_pat(&*node.pat);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_rest<'ast, V>(v: &mut V, node: &'ast PatRest)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.dot2_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_slice<'ast, V>(v: &mut V, node: &'ast PatSlice)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.bracket_token.span);
+ for el in Punctuated::pairs(&node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_pat(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_struct<'ast, V>(v: &mut V, node: &'ast PatStruct)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_path(&node.path);
+ tokens_helper(v, &node.brace_token.span);
+ for el in Punctuated::pairs(&node.fields) {
+ let (it, p) = el.into_tuple();
+ v.visit_field_pat(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ if let Some(it) = &node.dot2_token {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_tuple<'ast, V>(v: &mut V, node: &'ast PatTuple)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_pat(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_tuple_struct<'ast, V>(v: &mut V, node: &'ast PatTupleStruct)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_path(&node.path);
+ v.visit_pat_tuple(&node.pat);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_type<'ast, V>(v: &mut V, node: &'ast PatType)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_pat(&*node.pat);
+ tokens_helper(v, &node.colon_token.spans);
+ v.visit_type(&*node.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_wild<'ast, V>(v: &mut V, node: &'ast PatWild)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.underscore_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_path<'ast, V>(v: &mut V, node: &'ast Path)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.leading_colon {
+ tokens_helper(v, &it.spans)
+ };
+ for el in Punctuated::pairs(&node.segments) {
+ let (it, p) = el.into_tuple();
+ v.visit_path_segment(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_path_arguments<'ast, V>(v: &mut V, node: &'ast PathArguments)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(_binding_0) => {
+ v.visit_angle_bracketed_generic_arguments(_binding_0);
+ }
+ PathArguments::Parenthesized(_binding_0) => {
+ v.visit_parenthesized_generic_arguments(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_path_segment<'ast, V>(v: &mut V, node: &'ast PathSegment)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_ident(&node.ident);
+ v.visit_path_arguments(&node.arguments);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_predicate_eq<'ast, V>(v: &mut V, node: &'ast PredicateEq)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_type(&node.lhs_ty);
+ tokens_helper(v, &node.eq_token.spans);
+ v.visit_type(&node.rhs_ty);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_predicate_lifetime<'ast, V>(v: &mut V, node: &'ast PredicateLifetime)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_lifetime(&node.lifetime);
+ tokens_helper(v, &node.colon_token.spans);
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_lifetime(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_predicate_type<'ast, V>(v: &mut V, node: &'ast PredicateType)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.lifetimes {
+ v.visit_bound_lifetimes(it)
+ };
+ v.visit_type(&node.bounded_ty);
+ tokens_helper(v, &node.colon_token.spans);
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_qself<'ast, V>(v: &mut V, node: &'ast QSelf)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.lt_token.spans);
+ v.visit_type(&*node.ty);
+ skip!(node.position);
+ if let Some(it) = &node.as_token {
+ tokens_helper(v, &it.span)
+ };
+ tokens_helper(v, &node.gt_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_range_limits<'ast, V>(v: &mut V, node: &'ast RangeLimits)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ RangeLimits::HalfOpen(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ RangeLimits::Closed(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_receiver<'ast, V>(v: &mut V, node: &'ast Receiver)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ if let Some(it) = &node.reference {
+ tokens_helper(v, &(it).0.spans);
+ if let Some(it) = &(it).1 {
+ v.visit_lifetime(it)
+ };
+ };
+ if let Some(it) = &node.mutability {
+ tokens_helper(v, &it.span)
+ };
+ tokens_helper(v, &node.self_token.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_return_type<'ast, V>(v: &mut V, node: &'ast ReturnType)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ ReturnType::Default => {}
+ ReturnType::Type(_binding_0, _binding_1) => {
+ tokens_helper(v, &_binding_0.spans);
+ v.visit_type(&**_binding_1);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_signature<'ast, V>(v: &mut V, node: &'ast Signature)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.constness {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.asyncness {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.unsafety {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.abi {
+ v.visit_abi(it)
+ };
+ tokens_helper(v, &node.fn_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.inputs) {
+ let (it, p) = el.into_tuple();
+ v.visit_fn_arg(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ if let Some(it) = &node.variadic {
+ v.visit_variadic(it)
+ };
+ v.visit_return_type(&node.output);
+}
+pub fn visit_span<'ast, V>(v: &mut V, node: &Span)
+where
+ V: Visit<'ast> + ?Sized,
+{
+}
+#[cfg(feature = "full")]
+pub fn visit_stmt<'ast, V>(v: &mut V, node: &'ast Stmt)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Stmt::Local(_binding_0) => {
+ v.visit_local(_binding_0);
+ }
+ Stmt::Item(_binding_0) => {
+ v.visit_item(_binding_0);
+ }
+ Stmt::Expr(_binding_0) => {
+ v.visit_expr(_binding_0);
+ }
+ Stmt::Semi(_binding_0, _binding_1) => {
+ v.visit_expr(_binding_0);
+ tokens_helper(v, &_binding_1.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_trait_bound<'ast, V>(v: &mut V, node: &'ast TraitBound)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.paren_token {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_trait_bound_modifier(&node.modifier);
+ if let Some(it) = &node.lifetimes {
+ v.visit_bound_lifetimes(it)
+ };
+ v.visit_path(&node.path);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_trait_bound_modifier<'ast, V>(v: &mut V, node: &'ast TraitBoundModifier)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ TraitBoundModifier::None => {}
+ TraitBoundModifier::Maybe(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item<'ast, V>(v: &mut V, node: &'ast TraitItem)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ TraitItem::Const(_binding_0) => {
+ v.visit_trait_item_const(_binding_0);
+ }
+ TraitItem::Method(_binding_0) => {
+ v.visit_trait_item_method(_binding_0);
+ }
+ TraitItem::Type(_binding_0) => {
+ v.visit_trait_item_type(_binding_0);
+ }
+ TraitItem::Macro(_binding_0) => {
+ v.visit_trait_item_macro(_binding_0);
+ }
+ TraitItem::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_const<'ast, V>(v: &mut V, node: &'ast TraitItemConst)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.const_token.span);
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.colon_token.spans);
+ v.visit_type(&node.ty);
+ if let Some(it) = &node.default {
+ tokens_helper(v, &(it).0.spans);
+ v.visit_expr(&(it).1);
+ };
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_macro<'ast, V>(v: &mut V, node: &'ast TraitItemMacro)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_macro(&node.mac);
+ if let Some(it) = &node.semi_token {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_method<'ast, V>(v: &mut V, node: &'ast TraitItemMethod)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_signature(&node.sig);
+ if let Some(it) = &node.default {
+ v.visit_block(it)
+ };
+ if let Some(it) = &node.semi_token {
+ tokens_helper(v, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_type<'ast, V>(v: &mut V, node: &'ast TraitItemType)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.type_token.span);
+ v.visit_ident(&node.ident);
+ v.visit_generics(&node.generics);
+ if let Some(it) = &node.colon_token {
+ tokens_helper(v, &it.spans)
+ };
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ if let Some(it) = &node.default {
+ tokens_helper(v, &(it).0.spans);
+ v.visit_type(&(it).1);
+ };
+ tokens_helper(v, &node.semi_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type<'ast, V>(v: &mut V, node: &'ast Type)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Type::Array(_binding_0) => {
+ v.visit_type_array(_binding_0);
+ }
+ Type::BareFn(_binding_0) => {
+ v.visit_type_bare_fn(_binding_0);
+ }
+ Type::Group(_binding_0) => {
+ v.visit_type_group(_binding_0);
+ }
+ Type::ImplTrait(_binding_0) => {
+ v.visit_type_impl_trait(_binding_0);
+ }
+ Type::Infer(_binding_0) => {
+ v.visit_type_infer(_binding_0);
+ }
+ Type::Macro(_binding_0) => {
+ v.visit_type_macro(_binding_0);
+ }
+ Type::Never(_binding_0) => {
+ v.visit_type_never(_binding_0);
+ }
+ Type::Paren(_binding_0) => {
+ v.visit_type_paren(_binding_0);
+ }
+ Type::Path(_binding_0) => {
+ v.visit_type_path(_binding_0);
+ }
+ Type::Ptr(_binding_0) => {
+ v.visit_type_ptr(_binding_0);
+ }
+ Type::Reference(_binding_0) => {
+ v.visit_type_reference(_binding_0);
+ }
+ Type::Slice(_binding_0) => {
+ v.visit_type_slice(_binding_0);
+ }
+ Type::TraitObject(_binding_0) => {
+ v.visit_type_trait_object(_binding_0);
+ }
+ Type::Tuple(_binding_0) => {
+ v.visit_type_tuple(_binding_0);
+ }
+ Type::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_array<'ast, V>(v: &mut V, node: &'ast TypeArray)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.bracket_token.span);
+ v.visit_type(&*node.elem);
+ tokens_helper(v, &node.semi_token.spans);
+ v.visit_expr(&node.len);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_bare_fn<'ast, V>(v: &mut V, node: &'ast TypeBareFn)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.lifetimes {
+ v.visit_bound_lifetimes(it)
+ };
+ if let Some(it) = &node.unsafety {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.abi {
+ v.visit_abi(it)
+ };
+ tokens_helper(v, &node.fn_token.span);
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.inputs) {
+ let (it, p) = el.into_tuple();
+ v.visit_bare_fn_arg(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ if let Some(it) = &node.variadic {
+ v.visit_variadic(it)
+ };
+ v.visit_return_type(&node.output);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_group<'ast, V>(v: &mut V, node: &'ast TypeGroup)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.group_token.span);
+ v.visit_type(&*node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_impl_trait<'ast, V>(v: &mut V, node: &'ast TypeImplTrait)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.impl_token.span);
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_infer<'ast, V>(v: &mut V, node: &'ast TypeInfer)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.underscore_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_macro<'ast, V>(v: &mut V, node: &'ast TypeMacro)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_macro(&node.mac);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_never<'ast, V>(v: &mut V, node: &'ast TypeNever)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.bang_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_param<'ast, V>(v: &mut V, node: &'ast TypeParam)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_ident(&node.ident);
+ if let Some(it) = &node.colon_token {
+ tokens_helper(v, &it.spans)
+ };
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+ if let Some(it) = &node.eq_token {
+ tokens_helper(v, &it.spans)
+ };
+ if let Some(it) = &node.default {
+ v.visit_type(it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_param_bound<'ast, V>(v: &mut V, node: &'ast TypeParamBound)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ TypeParamBound::Trait(_binding_0) => {
+ v.visit_trait_bound(_binding_0);
+ }
+ TypeParamBound::Lifetime(_binding_0) => {
+ v.visit_lifetime(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_paren<'ast, V>(v: &mut V, node: &'ast TypeParen)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.paren_token.span);
+ v.visit_type(&*node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_path<'ast, V>(v: &mut V, node: &'ast TypePath)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.qself {
+ v.visit_qself(it)
+ };
+ v.visit_path(&node.path);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_ptr<'ast, V>(v: &mut V, node: &'ast TypePtr)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.star_token.spans);
+ if let Some(it) = &node.const_token {
+ tokens_helper(v, &it.span)
+ };
+ if let Some(it) = &node.mutability {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_type(&*node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_reference<'ast, V>(v: &mut V, node: &'ast TypeReference)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.and_token.spans);
+ if let Some(it) = &node.lifetime {
+ v.visit_lifetime(it)
+ };
+ if let Some(it) = &node.mutability {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_type(&*node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_slice<'ast, V>(v: &mut V, node: &'ast TypeSlice)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.bracket_token.span);
+ v.visit_type(&*node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_trait_object<'ast, V>(v: &mut V, node: &'ast TypeTraitObject)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ if let Some(it) = &node.dyn_token {
+ tokens_helper(v, &it.span)
+ };
+ for el in Punctuated::pairs(&node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_tuple<'ast, V>(v: &mut V, node: &'ast TypeTuple)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.paren_token.span);
+ for el in Punctuated::pairs(&node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_type(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_un_op<'ast, V>(v: &mut V, node: &'ast UnOp)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ UnOp::Deref(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ UnOp::Not(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ UnOp::Neg(_binding_0) => {
+ tokens_helper(v, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_use_glob<'ast, V>(v: &mut V, node: &'ast UseGlob)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.star_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_group<'ast, V>(v: &mut V, node: &'ast UseGroup)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.brace_token.span);
+ for el in Punctuated::pairs(&node.items) {
+ let (it, p) = el.into_tuple();
+ v.visit_use_tree(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_use_name<'ast, V>(v: &mut V, node: &'ast UseName)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_ident(&node.ident);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_path<'ast, V>(v: &mut V, node: &'ast UsePath)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.colon2_token.spans);
+ v.visit_use_tree(&*node.tree);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_rename<'ast, V>(v: &mut V, node: &'ast UseRename)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ v.visit_ident(&node.ident);
+ tokens_helper(v, &node.as_token.span);
+ v.visit_ident(&node.rename);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_tree<'ast, V>(v: &mut V, node: &'ast UseTree)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ UseTree::Path(_binding_0) => {
+ v.visit_use_path(_binding_0);
+ }
+ UseTree::Name(_binding_0) => {
+ v.visit_use_name(_binding_0);
+ }
+ UseTree::Rename(_binding_0) => {
+ v.visit_use_rename(_binding_0);
+ }
+ UseTree::Glob(_binding_0) => {
+ v.visit_use_glob(_binding_0);
+ }
+ UseTree::Group(_binding_0) => {
+ v.visit_use_group(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_variadic<'ast, V>(v: &mut V, node: &'ast Variadic)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ tokens_helper(v, &node.dots.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_variant<'ast, V>(v: &mut V, node: &'ast Variant)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ for it in &node.attrs {
+ v.visit_attribute(it)
+ }
+ v.visit_ident(&node.ident);
+ v.visit_fields(&node.fields);
+ if let Some(it) = &node.discriminant {
+ tokens_helper(v, &(it).0.spans);
+ v.visit_expr(&(it).1);
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_vis_crate<'ast, V>(v: &mut V, node: &'ast VisCrate)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.crate_token.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_vis_public<'ast, V>(v: &mut V, node: &'ast VisPublic)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.pub_token.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_vis_restricted<'ast, V>(v: &mut V, node: &'ast VisRestricted)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.pub_token.span);
+ tokens_helper(v, &node.paren_token.span);
+ if let Some(it) = &node.in_token {
+ tokens_helper(v, &it.span)
+ };
+ v.visit_path(&*node.path);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_visibility<'ast, V>(v: &mut V, node: &'ast Visibility)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ Visibility::Public(_binding_0) => {
+ v.visit_vis_public(_binding_0);
+ }
+ Visibility::Crate(_binding_0) => {
+ v.visit_vis_crate(_binding_0);
+ }
+ Visibility::Restricted(_binding_0) => {
+ v.visit_vis_restricted(_binding_0);
+ }
+ Visibility::Inherited => {}
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_where_clause<'ast, V>(v: &mut V, node: &'ast WhereClause)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ tokens_helper(v, &node.where_token.span);
+ for el in Punctuated::pairs(&node.predicates) {
+ let (it, p) = el.into_tuple();
+ v.visit_where_predicate(it);
+ if let Some(p) = p {
+ tokens_helper(v, &p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_where_predicate<'ast, V>(v: &mut V, node: &'ast WherePredicate)
+where
+ V: Visit<'ast> + ?Sized,
+{
+ match node {
+ WherePredicate::Type(_binding_0) => {
+ v.visit_predicate_type(_binding_0);
+ }
+ WherePredicate::Lifetime(_binding_0) => {
+ v.visit_predicate_lifetime(_binding_0);
+ }
+ WherePredicate::Eq(_binding_0) => {
+ v.visit_predicate_eq(_binding_0);
+ }
+ }
+}
diff --git a/syn/src/gen/visit_mut.rs b/syn/src/gen/visit_mut.rs
new file mode 100644
index 0000000..5cddb82
--- /dev/null
+++ b/syn/src/gen/visit_mut.rs
@@ -0,0 +1,3798 @@
+// This file is @generated by syn-internal-codegen.
+// It is not intended for manual editing.
+
+#![allow(unused_variables)]
+#[cfg(any(feature = "full", feature = "derive"))]
+use crate::gen::helper::visit_mut::*;
+#[cfg(any(feature = "full", feature = "derive"))]
+use crate::punctuated::Punctuated;
+use crate::*;
+use proc_macro2::Span;
+#[cfg(feature = "full")]
+macro_rules! full {
+ ($e:expr) => {
+ $e
+ };
+}
+#[cfg(all(feature = "derive", not(feature = "full")))]
+macro_rules! full {
+ ($e:expr) => {
+ unreachable!()
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! skip {
+ ($($tt:tt)*) => {};
+}
+/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
+/// place.
+///
+/// See the [module documentation] for details.
+///
+/// [module documentation]: self
+///
+/// *This trait is available if Syn is built with the `"visit-mut"` feature.*
+pub trait VisitMut {
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_abi_mut(&mut self, i: &mut Abi) {
+ visit_abi_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_angle_bracketed_generic_arguments_mut(
+ &mut self,
+ i: &mut AngleBracketedGenericArguments,
+ ) {
+ visit_angle_bracketed_generic_arguments_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_arm_mut(&mut self, i: &mut Arm) {
+ visit_arm_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_attr_style_mut(&mut self, i: &mut AttrStyle) {
+ visit_attr_style_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_attribute_mut(&mut self, i: &mut Attribute) {
+ visit_attribute_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_bare_fn_arg_mut(&mut self, i: &mut BareFnArg) {
+ visit_bare_fn_arg_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_bin_op_mut(&mut self, i: &mut BinOp) {
+ visit_bin_op_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_binding_mut(&mut self, i: &mut Binding) {
+ visit_binding_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_block_mut(&mut self, i: &mut Block) {
+ visit_block_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_bound_lifetimes_mut(&mut self, i: &mut BoundLifetimes) {
+ visit_bound_lifetimes_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_const_param_mut(&mut self, i: &mut ConstParam) {
+ visit_const_param_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_constraint_mut(&mut self, i: &mut Constraint) {
+ visit_constraint_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_mut(&mut self, i: &mut Data) {
+ visit_data_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_enum_mut(&mut self, i: &mut DataEnum) {
+ visit_data_enum_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_struct_mut(&mut self, i: &mut DataStruct) {
+ visit_data_struct_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_union_mut(&mut self, i: &mut DataUnion) {
+ visit_data_union_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_derive_input_mut(&mut self, i: &mut DeriveInput) {
+ visit_derive_input_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_mut(&mut self, i: &mut Expr) {
+ visit_expr_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_array_mut(&mut self, i: &mut ExprArray) {
+ visit_expr_array_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_assign_mut(&mut self, i: &mut ExprAssign) {
+ visit_expr_assign_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_assign_op_mut(&mut self, i: &mut ExprAssignOp) {
+ visit_expr_assign_op_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_async_mut(&mut self, i: &mut ExprAsync) {
+ visit_expr_async_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_await_mut(&mut self, i: &mut ExprAwait) {
+ visit_expr_await_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_binary_mut(&mut self, i: &mut ExprBinary) {
+ visit_expr_binary_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_block_mut(&mut self, i: &mut ExprBlock) {
+ visit_expr_block_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_box_mut(&mut self, i: &mut ExprBox) {
+ visit_expr_box_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_break_mut(&mut self, i: &mut ExprBreak) {
+ visit_expr_break_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_call_mut(&mut self, i: &mut ExprCall) {
+ visit_expr_call_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_cast_mut(&mut self, i: &mut ExprCast) {
+ visit_expr_cast_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_closure_mut(&mut self, i: &mut ExprClosure) {
+ visit_expr_closure_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_continue_mut(&mut self, i: &mut ExprContinue) {
+ visit_expr_continue_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_field_mut(&mut self, i: &mut ExprField) {
+ visit_expr_field_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_for_loop_mut(&mut self, i: &mut ExprForLoop) {
+ visit_expr_for_loop_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_group_mut(&mut self, i: &mut ExprGroup) {
+ visit_expr_group_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_if_mut(&mut self, i: &mut ExprIf) {
+ visit_expr_if_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_index_mut(&mut self, i: &mut ExprIndex) {
+ visit_expr_index_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_let_mut(&mut self, i: &mut ExprLet) {
+ visit_expr_let_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_lit_mut(&mut self, i: &mut ExprLit) {
+ visit_expr_lit_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_loop_mut(&mut self, i: &mut ExprLoop) {
+ visit_expr_loop_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_macro_mut(&mut self, i: &mut ExprMacro) {
+ visit_expr_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_match_mut(&mut self, i: &mut ExprMatch) {
+ visit_expr_match_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_method_call_mut(&mut self, i: &mut ExprMethodCall) {
+ visit_expr_method_call_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_paren_mut(&mut self, i: &mut ExprParen) {
+ visit_expr_paren_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_path_mut(&mut self, i: &mut ExprPath) {
+ visit_expr_path_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_range_mut(&mut self, i: &mut ExprRange) {
+ visit_expr_range_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_reference_mut(&mut self, i: &mut ExprReference) {
+ visit_expr_reference_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_repeat_mut(&mut self, i: &mut ExprRepeat) {
+ visit_expr_repeat_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_return_mut(&mut self, i: &mut ExprReturn) {
+ visit_expr_return_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_struct_mut(&mut self, i: &mut ExprStruct) {
+ visit_expr_struct_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_try_mut(&mut self, i: &mut ExprTry) {
+ visit_expr_try_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_try_block_mut(&mut self, i: &mut ExprTryBlock) {
+ visit_expr_try_block_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_tuple_mut(&mut self, i: &mut ExprTuple) {
+ visit_expr_tuple_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_type_mut(&mut self, i: &mut ExprType) {
+ visit_expr_type_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_expr_unary_mut(&mut self, i: &mut ExprUnary) {
+ visit_expr_unary_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_unsafe_mut(&mut self, i: &mut ExprUnsafe) {
+ visit_expr_unsafe_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_while_mut(&mut self, i: &mut ExprWhile) {
+ visit_expr_while_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr_yield_mut(&mut self, i: &mut ExprYield) {
+ visit_expr_yield_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_field_mut(&mut self, i: &mut Field) {
+ visit_field_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_field_pat_mut(&mut self, i: &mut FieldPat) {
+ visit_field_pat_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_field_value_mut(&mut self, i: &mut FieldValue) {
+ visit_field_value_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_fields_mut(&mut self, i: &mut Fields) {
+ visit_fields_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_fields_named_mut(&mut self, i: &mut FieldsNamed) {
+ visit_fields_named_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_fields_unnamed_mut(&mut self, i: &mut FieldsUnnamed) {
+ visit_fields_unnamed_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_file_mut(&mut self, i: &mut File) {
+ visit_file_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_fn_arg_mut(&mut self, i: &mut FnArg) {
+ visit_fn_arg_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_mut(&mut self, i: &mut ForeignItem) {
+ visit_foreign_item_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_fn_mut(&mut self, i: &mut ForeignItemFn) {
+ visit_foreign_item_fn_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_macro_mut(&mut self, i: &mut ForeignItemMacro) {
+ visit_foreign_item_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_static_mut(&mut self, i: &mut ForeignItemStatic) {
+ visit_foreign_item_static_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_type_mut(&mut self, i: &mut ForeignItemType) {
+ visit_foreign_item_type_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_generic_argument_mut(&mut self, i: &mut GenericArgument) {
+ visit_generic_argument_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_generic_method_argument_mut(&mut self, i: &mut GenericMethodArgument) {
+ visit_generic_method_argument_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_generic_param_mut(&mut self, i: &mut GenericParam) {
+ visit_generic_param_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_generics_mut(&mut self, i: &mut Generics) {
+ visit_generics_mut(self, i)
+ }
+ fn visit_ident_mut(&mut self, i: &mut Ident) {
+ visit_ident_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_mut(&mut self, i: &mut ImplItem) {
+ visit_impl_item_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_const_mut(&mut self, i: &mut ImplItemConst) {
+ visit_impl_item_const_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_macro_mut(&mut self, i: &mut ImplItemMacro) {
+ visit_impl_item_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_method_mut(&mut self, i: &mut ImplItemMethod) {
+ visit_impl_item_method_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_type_mut(&mut self, i: &mut ImplItemType) {
+ visit_impl_item_type_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_index_mut(&mut self, i: &mut Index) {
+ visit_index_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_mut(&mut self, i: &mut Item) {
+ visit_item_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_const_mut(&mut self, i: &mut ItemConst) {
+ visit_item_const_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_enum_mut(&mut self, i: &mut ItemEnum) {
+ visit_item_enum_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_extern_crate_mut(&mut self, i: &mut ItemExternCrate) {
+ visit_item_extern_crate_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_fn_mut(&mut self, i: &mut ItemFn) {
+ visit_item_fn_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_foreign_mod_mut(&mut self, i: &mut ItemForeignMod) {
+ visit_item_foreign_mod_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_impl_mut(&mut self, i: &mut ItemImpl) {
+ visit_item_impl_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_macro_mut(&mut self, i: &mut ItemMacro) {
+ visit_item_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_macro2_mut(&mut self, i: &mut ItemMacro2) {
+ visit_item_macro2_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_mod_mut(&mut self, i: &mut ItemMod) {
+ visit_item_mod_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_static_mut(&mut self, i: &mut ItemStatic) {
+ visit_item_static_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_struct_mut(&mut self, i: &mut ItemStruct) {
+ visit_item_struct_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_trait_mut(&mut self, i: &mut ItemTrait) {
+ visit_item_trait_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_trait_alias_mut(&mut self, i: &mut ItemTraitAlias) {
+ visit_item_trait_alias_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_type_mut(&mut self, i: &mut ItemType) {
+ visit_item_type_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_union_mut(&mut self, i: &mut ItemUnion) {
+ visit_item_union_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_use_mut(&mut self, i: &mut ItemUse) {
+ visit_item_use_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_label_mut(&mut self, i: &mut Label) {
+ visit_label_mut(self, i)
+ }
+ fn visit_lifetime_mut(&mut self, i: &mut Lifetime) {
+ visit_lifetime_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lifetime_def_mut(&mut self, i: &mut LifetimeDef) {
+ visit_lifetime_def_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_mut(&mut self, i: &mut Lit) {
+ visit_lit_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_bool_mut(&mut self, i: &mut LitBool) {
+ visit_lit_bool_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_byte_mut(&mut self, i: &mut LitByte) {
+ visit_lit_byte_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_byte_str_mut(&mut self, i: &mut LitByteStr) {
+ visit_lit_byte_str_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_char_mut(&mut self, i: &mut LitChar) {
+ visit_lit_char_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_float_mut(&mut self, i: &mut LitFloat) {
+ visit_lit_float_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_int_mut(&mut self, i: &mut LitInt) {
+ visit_lit_int_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_lit_str_mut(&mut self, i: &mut LitStr) {
+ visit_lit_str_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_local_mut(&mut self, i: &mut Local) {
+ visit_local_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_macro_mut(&mut self, i: &mut Macro) {
+ visit_macro_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_macro_delimiter_mut(&mut self, i: &mut MacroDelimiter) {
+ visit_macro_delimiter_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_member_mut(&mut self, i: &mut Member) {
+ visit_member_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_meta_mut(&mut self, i: &mut Meta) {
+ visit_meta_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_meta_list_mut(&mut self, i: &mut MetaList) {
+ visit_meta_list_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_meta_name_value_mut(&mut self, i: &mut MetaNameValue) {
+ visit_meta_name_value_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_method_turbofish_mut(&mut self, i: &mut MethodTurbofish) {
+ visit_method_turbofish_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_nested_meta_mut(&mut self, i: &mut NestedMeta) {
+ visit_nested_meta_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_parenthesized_generic_arguments_mut(&mut self, i: &mut ParenthesizedGenericArguments) {
+ visit_parenthesized_generic_arguments_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_mut(&mut self, i: &mut Pat) {
+ visit_pat_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_box_mut(&mut self, i: &mut PatBox) {
+ visit_pat_box_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_ident_mut(&mut self, i: &mut PatIdent) {
+ visit_pat_ident_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_lit_mut(&mut self, i: &mut PatLit) {
+ visit_pat_lit_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_macro_mut(&mut self, i: &mut PatMacro) {
+ visit_pat_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_or_mut(&mut self, i: &mut PatOr) {
+ visit_pat_or_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_path_mut(&mut self, i: &mut PatPath) {
+ visit_pat_path_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_range_mut(&mut self, i: &mut PatRange) {
+ visit_pat_range_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_reference_mut(&mut self, i: &mut PatReference) {
+ visit_pat_reference_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_rest_mut(&mut self, i: &mut PatRest) {
+ visit_pat_rest_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_slice_mut(&mut self, i: &mut PatSlice) {
+ visit_pat_slice_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_struct_mut(&mut self, i: &mut PatStruct) {
+ visit_pat_struct_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_tuple_mut(&mut self, i: &mut PatTuple) {
+ visit_pat_tuple_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_tuple_struct_mut(&mut self, i: &mut PatTupleStruct) {
+ visit_pat_tuple_struct_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_type_mut(&mut self, i: &mut PatType) {
+ visit_pat_type_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat_wild_mut(&mut self, i: &mut PatWild) {
+ visit_pat_wild_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_path_mut(&mut self, i: &mut Path) {
+ visit_path_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_path_arguments_mut(&mut self, i: &mut PathArguments) {
+ visit_path_arguments_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_path_segment_mut(&mut self, i: &mut PathSegment) {
+ visit_path_segment_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_predicate_eq_mut(&mut self, i: &mut PredicateEq) {
+ visit_predicate_eq_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_predicate_lifetime_mut(&mut self, i: &mut PredicateLifetime) {
+ visit_predicate_lifetime_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_predicate_type_mut(&mut self, i: &mut PredicateType) {
+ visit_predicate_type_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_qself_mut(&mut self, i: &mut QSelf) {
+ visit_qself_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_range_limits_mut(&mut self, i: &mut RangeLimits) {
+ visit_range_limits_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_receiver_mut(&mut self, i: &mut Receiver) {
+ visit_receiver_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_return_type_mut(&mut self, i: &mut ReturnType) {
+ visit_return_type_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_signature_mut(&mut self, i: &mut Signature) {
+ visit_signature_mut(self, i)
+ }
+ fn visit_span_mut(&mut self, i: &mut Span) {
+ visit_span_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_stmt_mut(&mut self, i: &mut Stmt) {
+ visit_stmt_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_trait_bound_mut(&mut self, i: &mut TraitBound) {
+ visit_trait_bound_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_trait_bound_modifier_mut(&mut self, i: &mut TraitBoundModifier) {
+ visit_trait_bound_modifier_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_mut(&mut self, i: &mut TraitItem) {
+ visit_trait_item_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_const_mut(&mut self, i: &mut TraitItemConst) {
+ visit_trait_item_const_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_macro_mut(&mut self, i: &mut TraitItemMacro) {
+ visit_trait_item_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_method_mut(&mut self, i: &mut TraitItemMethod) {
+ visit_trait_item_method_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_type_mut(&mut self, i: &mut TraitItemType) {
+ visit_trait_item_type_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_mut(&mut self, i: &mut Type) {
+ visit_type_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_array_mut(&mut self, i: &mut TypeArray) {
+ visit_type_array_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_bare_fn_mut(&mut self, i: &mut TypeBareFn) {
+ visit_type_bare_fn_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_group_mut(&mut self, i: &mut TypeGroup) {
+ visit_type_group_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_impl_trait_mut(&mut self, i: &mut TypeImplTrait) {
+ visit_type_impl_trait_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_infer_mut(&mut self, i: &mut TypeInfer) {
+ visit_type_infer_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_macro_mut(&mut self, i: &mut TypeMacro) {
+ visit_type_macro_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_never_mut(&mut self, i: &mut TypeNever) {
+ visit_type_never_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_param_mut(&mut self, i: &mut TypeParam) {
+ visit_type_param_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_param_bound_mut(&mut self, i: &mut TypeParamBound) {
+ visit_type_param_bound_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_paren_mut(&mut self, i: &mut TypeParen) {
+ visit_type_paren_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_path_mut(&mut self, i: &mut TypePath) {
+ visit_type_path_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_ptr_mut(&mut self, i: &mut TypePtr) {
+ visit_type_ptr_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_reference_mut(&mut self, i: &mut TypeReference) {
+ visit_type_reference_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_slice_mut(&mut self, i: &mut TypeSlice) {
+ visit_type_slice_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_trait_object_mut(&mut self, i: &mut TypeTraitObject) {
+ visit_type_trait_object_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_type_tuple_mut(&mut self, i: &mut TypeTuple) {
+ visit_type_tuple_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_un_op_mut(&mut self, i: &mut UnOp) {
+ visit_un_op_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_glob_mut(&mut self, i: &mut UseGlob) {
+ visit_use_glob_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_group_mut(&mut self, i: &mut UseGroup) {
+ visit_use_group_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_name_mut(&mut self, i: &mut UseName) {
+ visit_use_name_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_path_mut(&mut self, i: &mut UsePath) {
+ visit_use_path_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_rename_mut(&mut self, i: &mut UseRename) {
+ visit_use_rename_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_tree_mut(&mut self, i: &mut UseTree) {
+ visit_use_tree_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_variadic_mut(&mut self, i: &mut Variadic) {
+ visit_variadic_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_variant_mut(&mut self, i: &mut Variant) {
+ visit_variant_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_vis_crate_mut(&mut self, i: &mut VisCrate) {
+ visit_vis_crate_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_vis_public_mut(&mut self, i: &mut VisPublic) {
+ visit_vis_public_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_vis_restricted_mut(&mut self, i: &mut VisRestricted) {
+ visit_vis_restricted_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_visibility_mut(&mut self, i: &mut Visibility) {
+ visit_visibility_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_where_clause_mut(&mut self, i: &mut WhereClause) {
+ visit_where_clause_mut(self, i)
+ }
+ #[cfg(any(feature = "derive", feature = "full"))]
+ fn visit_where_predicate_mut(&mut self, i: &mut WherePredicate) {
+ visit_where_predicate_mut(self, i)
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_abi_mut<V>(v: &mut V, node: &mut Abi)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.extern_token.span);
+ if let Some(it) = &mut node.name {
+ v.visit_lit_str_mut(it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_angle_bracketed_generic_arguments_mut<V>(
+ v: &mut V,
+ node: &mut AngleBracketedGenericArguments,
+) where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.colon2_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ tokens_helper(v, &mut node.lt_token.spans);
+ for el in Punctuated::pairs_mut(&mut node.args) {
+ let (it, p) = el.into_tuple();
+ v.visit_generic_argument_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ tokens_helper(v, &mut node.gt_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_arm_mut<V>(v: &mut V, node: &mut Arm)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_pat_mut(&mut node.pat);
+ if let Some(it) = &mut node.guard {
+ tokens_helper(v, &mut (it).0.span);
+ v.visit_expr_mut(&mut *(it).1);
+ };
+ tokens_helper(v, &mut node.fat_arrow_token.spans);
+ v.visit_expr_mut(&mut *node.body);
+ if let Some(it) = &mut node.comma {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_attr_style_mut<V>(v: &mut V, node: &mut AttrStyle)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ AttrStyle::Outer => {}
+ AttrStyle::Inner(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_attribute_mut<V>(v: &mut V, node: &mut Attribute)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.pound_token.spans);
+ v.visit_attr_style_mut(&mut node.style);
+ tokens_helper(v, &mut node.bracket_token.span);
+ v.visit_path_mut(&mut node.path);
+ skip!(node.tokens);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_bare_fn_arg_mut<V>(v: &mut V, node: &mut BareFnArg)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.name {
+ v.visit_ident_mut(&mut (it).0);
+ tokens_helper(v, &mut (it).1.spans);
+ };
+ v.visit_type_mut(&mut node.ty);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_bin_op_mut<V>(v: &mut V, node: &mut BinOp)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ BinOp::Add(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Sub(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Mul(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Div(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Rem(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::And(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Or(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::BitXor(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::BitAnd(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::BitOr(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Shl(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Shr(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Eq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Lt(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Le(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Ne(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Ge(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::Gt(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::AddEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::SubEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::MulEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::DivEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::RemEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::BitXorEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::BitAndEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::BitOrEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::ShlEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ BinOp::ShrEq(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_binding_mut<V>(v: &mut V, node: &mut Binding)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_type_mut(&mut node.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_block_mut<V>(v: &mut V, node: &mut Block)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.brace_token.span);
+ for it in &mut node.stmts {
+ v.visit_stmt_mut(it)
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_bound_lifetimes_mut<V>(v: &mut V, node: &mut BoundLifetimes)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.for_token.span);
+ tokens_helper(v, &mut node.lt_token.spans);
+ for el in Punctuated::pairs_mut(&mut node.lifetimes) {
+ let (it, p) = el.into_tuple();
+ v.visit_lifetime_def_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ tokens_helper(v, &mut node.gt_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_const_param_mut<V>(v: &mut V, node: &mut ConstParam)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.const_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.colon_token.spans);
+ v.visit_type_mut(&mut node.ty);
+ if let Some(it) = &mut node.eq_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ if let Some(it) = &mut node.default {
+ v.visit_expr_mut(it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_constraint_mut<V>(v: &mut V, node: &mut Constraint)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.colon_token.spans);
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_mut<V>(v: &mut V, node: &mut Data)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Data::Struct(_binding_0) => {
+ v.visit_data_struct_mut(_binding_0);
+ }
+ Data::Enum(_binding_0) => {
+ v.visit_data_enum_mut(_binding_0);
+ }
+ Data::Union(_binding_0) => {
+ v.visit_data_union_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_enum_mut<V>(v: &mut V, node: &mut DataEnum)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.enum_token.span);
+ tokens_helper(v, &mut node.brace_token.span);
+ for el in Punctuated::pairs_mut(&mut node.variants) {
+ let (it, p) = el.into_tuple();
+ v.visit_variant_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_struct_mut<V>(v: &mut V, node: &mut DataStruct)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.struct_token.span);
+ v.visit_fields_mut(&mut node.fields);
+ if let Some(it) = &mut node.semi_token {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_union_mut<V>(v: &mut V, node: &mut DataUnion)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.union_token.span);
+ v.visit_fields_named_mut(&mut node.fields);
+}
+#[cfg(feature = "derive")]
+pub fn visit_derive_input_mut<V>(v: &mut V, node: &mut DeriveInput)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ v.visit_data_mut(&mut node.data);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_mut<V>(v: &mut V, node: &mut Expr)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Expr::Array(_binding_0) => {
+ full!(v.visit_expr_array_mut(_binding_0));
+ }
+ Expr::Assign(_binding_0) => {
+ full!(v.visit_expr_assign_mut(_binding_0));
+ }
+ Expr::AssignOp(_binding_0) => {
+ full!(v.visit_expr_assign_op_mut(_binding_0));
+ }
+ Expr::Async(_binding_0) => {
+ full!(v.visit_expr_async_mut(_binding_0));
+ }
+ Expr::Await(_binding_0) => {
+ full!(v.visit_expr_await_mut(_binding_0));
+ }
+ Expr::Binary(_binding_0) => {
+ v.visit_expr_binary_mut(_binding_0);
+ }
+ Expr::Block(_binding_0) => {
+ full!(v.visit_expr_block_mut(_binding_0));
+ }
+ Expr::Box(_binding_0) => {
+ full!(v.visit_expr_box_mut(_binding_0));
+ }
+ Expr::Break(_binding_0) => {
+ full!(v.visit_expr_break_mut(_binding_0));
+ }
+ Expr::Call(_binding_0) => {
+ v.visit_expr_call_mut(_binding_0);
+ }
+ Expr::Cast(_binding_0) => {
+ v.visit_expr_cast_mut(_binding_0);
+ }
+ Expr::Closure(_binding_0) => {
+ full!(v.visit_expr_closure_mut(_binding_0));
+ }
+ Expr::Continue(_binding_0) => {
+ full!(v.visit_expr_continue_mut(_binding_0));
+ }
+ Expr::Field(_binding_0) => {
+ v.visit_expr_field_mut(_binding_0);
+ }
+ Expr::ForLoop(_binding_0) => {
+ full!(v.visit_expr_for_loop_mut(_binding_0));
+ }
+ Expr::Group(_binding_0) => {
+ full!(v.visit_expr_group_mut(_binding_0));
+ }
+ Expr::If(_binding_0) => {
+ full!(v.visit_expr_if_mut(_binding_0));
+ }
+ Expr::Index(_binding_0) => {
+ v.visit_expr_index_mut(_binding_0);
+ }
+ Expr::Let(_binding_0) => {
+ full!(v.visit_expr_let_mut(_binding_0));
+ }
+ Expr::Lit(_binding_0) => {
+ v.visit_expr_lit_mut(_binding_0);
+ }
+ Expr::Loop(_binding_0) => {
+ full!(v.visit_expr_loop_mut(_binding_0));
+ }
+ Expr::Macro(_binding_0) => {
+ full!(v.visit_expr_macro_mut(_binding_0));
+ }
+ Expr::Match(_binding_0) => {
+ full!(v.visit_expr_match_mut(_binding_0));
+ }
+ Expr::MethodCall(_binding_0) => {
+ full!(v.visit_expr_method_call_mut(_binding_0));
+ }
+ Expr::Paren(_binding_0) => {
+ v.visit_expr_paren_mut(_binding_0);
+ }
+ Expr::Path(_binding_0) => {
+ v.visit_expr_path_mut(_binding_0);
+ }
+ Expr::Range(_binding_0) => {
+ full!(v.visit_expr_range_mut(_binding_0));
+ }
+ Expr::Reference(_binding_0) => {
+ full!(v.visit_expr_reference_mut(_binding_0));
+ }
+ Expr::Repeat(_binding_0) => {
+ full!(v.visit_expr_repeat_mut(_binding_0));
+ }
+ Expr::Return(_binding_0) => {
+ full!(v.visit_expr_return_mut(_binding_0));
+ }
+ Expr::Struct(_binding_0) => {
+ full!(v.visit_expr_struct_mut(_binding_0));
+ }
+ Expr::Try(_binding_0) => {
+ full!(v.visit_expr_try_mut(_binding_0));
+ }
+ Expr::TryBlock(_binding_0) => {
+ full!(v.visit_expr_try_block_mut(_binding_0));
+ }
+ Expr::Tuple(_binding_0) => {
+ full!(v.visit_expr_tuple_mut(_binding_0));
+ }
+ Expr::Type(_binding_0) => {
+ full!(v.visit_expr_type_mut(_binding_0));
+ }
+ Expr::Unary(_binding_0) => {
+ v.visit_expr_unary_mut(_binding_0);
+ }
+ Expr::Unsafe(_binding_0) => {
+ full!(v.visit_expr_unsafe_mut(_binding_0));
+ }
+ Expr::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ Expr::While(_binding_0) => {
+ full!(v.visit_expr_while_mut(_binding_0));
+ }
+ Expr::Yield(_binding_0) => {
+ full!(v.visit_expr_yield_mut(_binding_0));
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_array_mut<V>(v: &mut V, node: &mut ExprArray)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.bracket_token.span);
+ for el in Punctuated::pairs_mut(&mut node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_expr_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_assign_mut<V>(v: &mut V, node: &mut ExprAssign)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.left);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_expr_mut(&mut *node.right);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_assign_op_mut<V>(v: &mut V, node: &mut ExprAssignOp)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.left);
+ v.visit_bin_op_mut(&mut node.op);
+ v.visit_expr_mut(&mut *node.right);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_async_mut<V>(v: &mut V, node: &mut ExprAsync)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.async_token.span);
+ if let Some(it) = &mut node.capture {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_block_mut(&mut node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_await_mut<V>(v: &mut V, node: &mut ExprAwait)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.base);
+ tokens_helper(v, &mut node.dot_token.spans);
+ tokens_helper(v, &mut node.await_token.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.left);
+ v.visit_bin_op_mut(&mut node.op);
+ v.visit_expr_mut(&mut *node.right);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_block_mut<V>(v: &mut V, node: &mut ExprBlock)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.label {
+ v.visit_label_mut(it)
+ };
+ v.visit_block_mut(&mut node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_box_mut<V>(v: &mut V, node: &mut ExprBox)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.box_token.span);
+ v.visit_expr_mut(&mut *node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_break_mut<V>(v: &mut V, node: &mut ExprBreak)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.break_token.span);
+ if let Some(it) = &mut node.label {
+ v.visit_lifetime_mut(it)
+ };
+ if let Some(it) = &mut node.expr {
+ v.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_call_mut<V>(v: &mut V, node: &mut ExprCall)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.func);
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.args) {
+ let (it, p) = el.into_tuple();
+ v.visit_expr_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_cast_mut<V>(v: &mut V, node: &mut ExprCast)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.expr);
+ tokens_helper(v, &mut node.as_token.span);
+ v.visit_type_mut(&mut *node.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_closure_mut<V>(v: &mut V, node: &mut ExprClosure)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.asyncness {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.movability {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.capture {
+ tokens_helper(v, &mut it.span)
+ };
+ tokens_helper(v, &mut node.or1_token.spans);
+ for el in Punctuated::pairs_mut(&mut node.inputs) {
+ let (it, p) = el.into_tuple();
+ v.visit_pat_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ tokens_helper(v, &mut node.or2_token.spans);
+ v.visit_return_type_mut(&mut node.output);
+ v.visit_expr_mut(&mut *node.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_continue_mut<V>(v: &mut V, node: &mut ExprContinue)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.continue_token.span);
+ if let Some(it) = &mut node.label {
+ v.visit_lifetime_mut(it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_field_mut<V>(v: &mut V, node: &mut ExprField)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.base);
+ tokens_helper(v, &mut node.dot_token.spans);
+ v.visit_member_mut(&mut node.member);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_for_loop_mut<V>(v: &mut V, node: &mut ExprForLoop)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.label {
+ v.visit_label_mut(it)
+ };
+ tokens_helper(v, &mut node.for_token.span);
+ v.visit_pat_mut(&mut node.pat);
+ tokens_helper(v, &mut node.in_token.span);
+ v.visit_expr_mut(&mut *node.expr);
+ v.visit_block_mut(&mut node.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_group_mut<V>(v: &mut V, node: &mut ExprGroup)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.group_token.span);
+ v.visit_expr_mut(&mut *node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_if_mut<V>(v: &mut V, node: &mut ExprIf)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.if_token.span);
+ v.visit_expr_mut(&mut *node.cond);
+ v.visit_block_mut(&mut node.then_branch);
+ if let Some(it) = &mut node.else_branch {
+ tokens_helper(v, &mut (it).0.span);
+ v.visit_expr_mut(&mut *(it).1);
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_index_mut<V>(v: &mut V, node: &mut ExprIndex)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.expr);
+ tokens_helper(v, &mut node.bracket_token.span);
+ v.visit_expr_mut(&mut *node.index);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_let_mut<V>(v: &mut V, node: &mut ExprLet)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.let_token.span);
+ v.visit_pat_mut(&mut node.pat);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_expr_mut(&mut *node.expr);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_lit_mut<V>(v: &mut V, node: &mut ExprLit)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_lit_mut(&mut node.lit);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_loop_mut<V>(v: &mut V, node: &mut ExprLoop)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.label {
+ v.visit_label_mut(it)
+ };
+ tokens_helper(v, &mut node.loop_token.span);
+ v.visit_block_mut(&mut node.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_macro_mut<V>(v: &mut V, node: &mut ExprMacro)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_macro_mut(&mut node.mac);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_match_mut<V>(v: &mut V, node: &mut ExprMatch)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.match_token.span);
+ v.visit_expr_mut(&mut *node.expr);
+ tokens_helper(v, &mut node.brace_token.span);
+ for it in &mut node.arms {
+ v.visit_arm_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_method_call_mut<V>(v: &mut V, node: &mut ExprMethodCall)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.receiver);
+ tokens_helper(v, &mut node.dot_token.spans);
+ v.visit_ident_mut(&mut node.method);
+ if let Some(it) = &mut node.turbofish {
+ v.visit_method_turbofish_mut(it)
+ };
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.args) {
+ let (it, p) = el.into_tuple();
+ v.visit_expr_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_paren_mut<V>(v: &mut V, node: &mut ExprParen)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.paren_token.span);
+ v.visit_expr_mut(&mut *node.expr);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_path_mut<V>(v: &mut V, node: &mut ExprPath)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.qself {
+ v.visit_qself_mut(it)
+ };
+ v.visit_path_mut(&mut node.path);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_range_mut<V>(v: &mut V, node: &mut ExprRange)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.from {
+ v.visit_expr_mut(&mut **it)
+ };
+ v.visit_range_limits_mut(&mut node.limits);
+ if let Some(it) = &mut node.to {
+ v.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_reference_mut<V>(v: &mut V, node: &mut ExprReference)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.and_token.spans);
+ if let Some(it) = &mut node.mutability {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_expr_mut(&mut *node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_repeat_mut<V>(v: &mut V, node: &mut ExprRepeat)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.bracket_token.span);
+ v.visit_expr_mut(&mut *node.expr);
+ tokens_helper(v, &mut node.semi_token.spans);
+ v.visit_expr_mut(&mut *node.len);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_return_mut<V>(v: &mut V, node: &mut ExprReturn)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.return_token.span);
+ if let Some(it) = &mut node.expr {
+ v.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_struct_mut<V>(v: &mut V, node: &mut ExprStruct)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_path_mut(&mut node.path);
+ tokens_helper(v, &mut node.brace_token.span);
+ for el in Punctuated::pairs_mut(&mut node.fields) {
+ let (it, p) = el.into_tuple();
+ v.visit_field_value_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ if let Some(it) = &mut node.dot2_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ if let Some(it) = &mut node.rest {
+ v.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_try_mut<V>(v: &mut V, node: &mut ExprTry)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.expr);
+ tokens_helper(v, &mut node.question_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_try_block_mut<V>(v: &mut V, node: &mut ExprTryBlock)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.try_token.span);
+ v.visit_block_mut(&mut node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_tuple_mut<V>(v: &mut V, node: &mut ExprTuple)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_expr_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_type_mut<V>(v: &mut V, node: &mut ExprType)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.expr);
+ tokens_helper(v, &mut node.colon_token.spans);
+ v.visit_type_mut(&mut *node.ty);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_expr_unary_mut<V>(v: &mut V, node: &mut ExprUnary)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_un_op_mut(&mut node.op);
+ v.visit_expr_mut(&mut *node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_unsafe_mut<V>(v: &mut V, node: &mut ExprUnsafe)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.unsafe_token.span);
+ v.visit_block_mut(&mut node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_while_mut<V>(v: &mut V, node: &mut ExprWhile)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.label {
+ v.visit_label_mut(it)
+ };
+ tokens_helper(v, &mut node.while_token.span);
+ v.visit_expr_mut(&mut *node.cond);
+ v.visit_block_mut(&mut node.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_expr_yield_mut<V>(v: &mut V, node: &mut ExprYield)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.yield_token.span);
+ if let Some(it) = &mut node.expr {
+ v.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_field_mut<V>(v: &mut V, node: &mut Field)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ if let Some(it) = &mut node.ident {
+ v.visit_ident_mut(it)
+ };
+ if let Some(it) = &mut node.colon_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ v.visit_type_mut(&mut node.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_field_pat_mut<V>(v: &mut V, node: &mut FieldPat)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_member_mut(&mut node.member);
+ if let Some(it) = &mut node.colon_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ v.visit_pat_mut(&mut *node.pat);
+}
+#[cfg(feature = "full")]
+pub fn visit_field_value_mut<V>(v: &mut V, node: &mut FieldValue)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_member_mut(&mut node.member);
+ if let Some(it) = &mut node.colon_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ v.visit_expr_mut(&mut node.expr);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_fields_mut<V>(v: &mut V, node: &mut Fields)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Fields::Named(_binding_0) => {
+ v.visit_fields_named_mut(_binding_0);
+ }
+ Fields::Unnamed(_binding_0) => {
+ v.visit_fields_unnamed_mut(_binding_0);
+ }
+ Fields::Unit => {}
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_fields_named_mut<V>(v: &mut V, node: &mut FieldsNamed)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.brace_token.span);
+ for el in Punctuated::pairs_mut(&mut node.named) {
+ let (it, p) = el.into_tuple();
+ v.visit_field_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_fields_unnamed_mut<V>(v: &mut V, node: &mut FieldsUnnamed)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.unnamed) {
+ let (it, p) = el.into_tuple();
+ v.visit_field_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_file_mut<V>(v: &mut V, node: &mut File)
+where
+ V: VisitMut + ?Sized,
+{
+ skip!(node.shebang);
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ for it in &mut node.items {
+ v.visit_item_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_fn_arg_mut<V>(v: &mut V, node: &mut FnArg)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ FnArg::Receiver(_binding_0) => {
+ v.visit_receiver_mut(_binding_0);
+ }
+ FnArg::Typed(_binding_0) => {
+ v.visit_pat_type_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_mut<V>(v: &mut V, node: &mut ForeignItem)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ ForeignItem::Fn(_binding_0) => {
+ v.visit_foreign_item_fn_mut(_binding_0);
+ }
+ ForeignItem::Static(_binding_0) => {
+ v.visit_foreign_item_static_mut(_binding_0);
+ }
+ ForeignItem::Type(_binding_0) => {
+ v.visit_foreign_item_type_mut(_binding_0);
+ }
+ ForeignItem::Macro(_binding_0) => {
+ v.visit_foreign_item_macro_mut(_binding_0);
+ }
+ ForeignItem::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_fn_mut<V>(v: &mut V, node: &mut ForeignItemFn)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ v.visit_signature_mut(&mut node.sig);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_macro_mut<V>(v: &mut V, node: &mut ForeignItemMacro)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_macro_mut(&mut node.mac);
+ if let Some(it) = &mut node.semi_token {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_static_mut<V>(v: &mut V, node: &mut ForeignItemStatic)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.static_token.span);
+ if let Some(it) = &mut node.mutability {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.colon_token.spans);
+ v.visit_type_mut(&mut *node.ty);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_type_mut<V>(v: &mut V, node: &mut ForeignItemType)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.type_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_generic_argument_mut<V>(v: &mut V, node: &mut GenericArgument)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ GenericArgument::Lifetime(_binding_0) => {
+ v.visit_lifetime_mut(_binding_0);
+ }
+ GenericArgument::Type(_binding_0) => {
+ v.visit_type_mut(_binding_0);
+ }
+ GenericArgument::Binding(_binding_0) => {
+ v.visit_binding_mut(_binding_0);
+ }
+ GenericArgument::Constraint(_binding_0) => {
+ v.visit_constraint_mut(_binding_0);
+ }
+ GenericArgument::Const(_binding_0) => {
+ v.visit_expr_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_generic_method_argument_mut<V>(v: &mut V, node: &mut GenericMethodArgument)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ GenericMethodArgument::Type(_binding_0) => {
+ v.visit_type_mut(_binding_0);
+ }
+ GenericMethodArgument::Const(_binding_0) => {
+ v.visit_expr_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_generic_param_mut<V>(v: &mut V, node: &mut GenericParam)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ GenericParam::Type(_binding_0) => {
+ v.visit_type_param_mut(_binding_0);
+ }
+ GenericParam::Lifetime(_binding_0) => {
+ v.visit_lifetime_def_mut(_binding_0);
+ }
+ GenericParam::Const(_binding_0) => {
+ v.visit_const_param_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_generics_mut<V>(v: &mut V, node: &mut Generics)
+where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.lt_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ for el in Punctuated::pairs_mut(&mut node.params) {
+ let (it, p) = el.into_tuple();
+ v.visit_generic_param_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ if let Some(it) = &mut node.gt_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ if let Some(it) = &mut node.where_clause {
+ v.visit_where_clause_mut(it)
+ };
+}
+pub fn visit_ident_mut<V>(v: &mut V, node: &mut Ident)
+where
+ V: VisitMut + ?Sized,
+{
+ let mut span = node.span();
+ v.visit_span_mut(&mut span);
+ node.set_span(span);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_mut<V>(v: &mut V, node: &mut ImplItem)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ ImplItem::Const(_binding_0) => {
+ v.visit_impl_item_const_mut(_binding_0);
+ }
+ ImplItem::Method(_binding_0) => {
+ v.visit_impl_item_method_mut(_binding_0);
+ }
+ ImplItem::Type(_binding_0) => {
+ v.visit_impl_item_type_mut(_binding_0);
+ }
+ ImplItem::Macro(_binding_0) => {
+ v.visit_impl_item_macro_mut(_binding_0);
+ }
+ ImplItem::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_const_mut<V>(v: &mut V, node: &mut ImplItemConst)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ if let Some(it) = &mut node.defaultness {
+ tokens_helper(v, &mut it.span)
+ };
+ tokens_helper(v, &mut node.const_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.colon_token.spans);
+ v.visit_type_mut(&mut node.ty);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_expr_mut(&mut node.expr);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_macro_mut<V>(v: &mut V, node: &mut ImplItemMacro)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_macro_mut(&mut node.mac);
+ if let Some(it) = &mut node.semi_token {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_method_mut<V>(v: &mut V, node: &mut ImplItemMethod)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ if let Some(it) = &mut node.defaultness {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_signature_mut(&mut node.sig);
+ v.visit_block_mut(&mut node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_type_mut<V>(v: &mut V, node: &mut ImplItemType)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ if let Some(it) = &mut node.defaultness {
+ tokens_helper(v, &mut it.span)
+ };
+ tokens_helper(v, &mut node.type_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_type_mut(&mut node.ty);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_index_mut<V>(v: &mut V, node: &mut Index)
+where
+ V: VisitMut + ?Sized,
+{
+ skip!(node.index);
+ v.visit_span_mut(&mut node.span);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_mut<V>(v: &mut V, node: &mut Item)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Item::Const(_binding_0) => {
+ v.visit_item_const_mut(_binding_0);
+ }
+ Item::Enum(_binding_0) => {
+ v.visit_item_enum_mut(_binding_0);
+ }
+ Item::ExternCrate(_binding_0) => {
+ v.visit_item_extern_crate_mut(_binding_0);
+ }
+ Item::Fn(_binding_0) => {
+ v.visit_item_fn_mut(_binding_0);
+ }
+ Item::ForeignMod(_binding_0) => {
+ v.visit_item_foreign_mod_mut(_binding_0);
+ }
+ Item::Impl(_binding_0) => {
+ v.visit_item_impl_mut(_binding_0);
+ }
+ Item::Macro(_binding_0) => {
+ v.visit_item_macro_mut(_binding_0);
+ }
+ Item::Macro2(_binding_0) => {
+ v.visit_item_macro2_mut(_binding_0);
+ }
+ Item::Mod(_binding_0) => {
+ v.visit_item_mod_mut(_binding_0);
+ }
+ Item::Static(_binding_0) => {
+ v.visit_item_static_mut(_binding_0);
+ }
+ Item::Struct(_binding_0) => {
+ v.visit_item_struct_mut(_binding_0);
+ }
+ Item::Trait(_binding_0) => {
+ v.visit_item_trait_mut(_binding_0);
+ }
+ Item::TraitAlias(_binding_0) => {
+ v.visit_item_trait_alias_mut(_binding_0);
+ }
+ Item::Type(_binding_0) => {
+ v.visit_item_type_mut(_binding_0);
+ }
+ Item::Union(_binding_0) => {
+ v.visit_item_union_mut(_binding_0);
+ }
+ Item::Use(_binding_0) => {
+ v.visit_item_use_mut(_binding_0);
+ }
+ Item::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_const_mut<V>(v: &mut V, node: &mut ItemConst)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.const_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.colon_token.spans);
+ v.visit_type_mut(&mut *node.ty);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_expr_mut(&mut *node.expr);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_enum_mut<V>(v: &mut V, node: &mut ItemEnum)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.enum_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ tokens_helper(v, &mut node.brace_token.span);
+ for el in Punctuated::pairs_mut(&mut node.variants) {
+ let (it, p) = el.into_tuple();
+ v.visit_variant_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_extern_crate_mut<V>(v: &mut V, node: &mut ItemExternCrate)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.extern_token.span);
+ tokens_helper(v, &mut node.crate_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ if let Some(it) = &mut node.rename {
+ tokens_helper(v, &mut (it).0.span);
+ v.visit_ident_mut(&mut (it).1);
+ };
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_fn_mut<V>(v: &mut V, node: &mut ItemFn)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ v.visit_signature_mut(&mut node.sig);
+ v.visit_block_mut(&mut *node.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_foreign_mod_mut<V>(v: &mut V, node: &mut ItemForeignMod)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_abi_mut(&mut node.abi);
+ tokens_helper(v, &mut node.brace_token.span);
+ for it in &mut node.items {
+ v.visit_foreign_item_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_impl_mut<V>(v: &mut V, node: &mut ItemImpl)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.defaultness {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.unsafety {
+ tokens_helper(v, &mut it.span)
+ };
+ tokens_helper(v, &mut node.impl_token.span);
+ v.visit_generics_mut(&mut node.generics);
+ if let Some(it) = &mut node.trait_ {
+ if let Some(it) = &mut (it).0 {
+ tokens_helper(v, &mut it.spans)
+ };
+ v.visit_path_mut(&mut (it).1);
+ tokens_helper(v, &mut (it).2.span);
+ };
+ v.visit_type_mut(&mut *node.self_ty);
+ tokens_helper(v, &mut node.brace_token.span);
+ for it in &mut node.items {
+ v.visit_impl_item_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_macro_mut<V>(v: &mut V, node: &mut ItemMacro)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.ident {
+ v.visit_ident_mut(it)
+ };
+ v.visit_macro_mut(&mut node.mac);
+ if let Some(it) = &mut node.semi_token {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_macro2_mut<V>(v: &mut V, node: &mut ItemMacro2)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.macro_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ skip!(node.rules);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_mod_mut<V>(v: &mut V, node: &mut ItemMod)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.mod_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ if let Some(it) = &mut node.content {
+ tokens_helper(v, &mut (it).0.span);
+ for it in &mut (it).1 {
+ v.visit_item_mut(it)
+ }
+ };
+ if let Some(it) = &mut node.semi {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_static_mut<V>(v: &mut V, node: &mut ItemStatic)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.static_token.span);
+ if let Some(it) = &mut node.mutability {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.colon_token.spans);
+ v.visit_type_mut(&mut *node.ty);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_expr_mut(&mut *node.expr);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_struct_mut<V>(v: &mut V, node: &mut ItemStruct)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.struct_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ v.visit_fields_mut(&mut node.fields);
+ if let Some(it) = &mut node.semi_token {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_trait_mut<V>(v: &mut V, node: &mut ItemTrait)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ if let Some(it) = &mut node.unsafety {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.auto_token {
+ tokens_helper(v, &mut it.span)
+ };
+ tokens_helper(v, &mut node.trait_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ if let Some(it) = &mut node.colon_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ for el in Punctuated::pairs_mut(&mut node.supertraits) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ tokens_helper(v, &mut node.brace_token.span);
+ for it in &mut node.items {
+ v.visit_trait_item_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_trait_alias_mut<V>(v: &mut V, node: &mut ItemTraitAlias)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.trait_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ tokens_helper(v, &mut node.eq_token.spans);
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_type_mut<V>(v: &mut V, node: &mut ItemType)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.type_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_type_mut(&mut *node.ty);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_union_mut<V>(v: &mut V, node: &mut ItemUnion)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.union_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ v.visit_fields_named_mut(&mut node.fields);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_use_mut<V>(v: &mut V, node: &mut ItemUse)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_visibility_mut(&mut node.vis);
+ tokens_helper(v, &mut node.use_token.span);
+ if let Some(it) = &mut node.leading_colon {
+ tokens_helper(v, &mut it.spans)
+ };
+ v.visit_use_tree_mut(&mut node.tree);
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_label_mut<V>(v: &mut V, node: &mut Label)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_lifetime_mut(&mut node.name);
+ tokens_helper(v, &mut node.colon_token.spans);
+}
+pub fn visit_lifetime_mut<V>(v: &mut V, node: &mut Lifetime)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_span_mut(&mut node.apostrophe);
+ v.visit_ident_mut(&mut node.ident);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lifetime_def_mut<V>(v: &mut V, node: &mut LifetimeDef)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_lifetime_mut(&mut node.lifetime);
+ if let Some(it) = &mut node.colon_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_lifetime_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_mut<V>(v: &mut V, node: &mut Lit)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Lit::Str(_binding_0) => {
+ v.visit_lit_str_mut(_binding_0);
+ }
+ Lit::ByteStr(_binding_0) => {
+ v.visit_lit_byte_str_mut(_binding_0);
+ }
+ Lit::Byte(_binding_0) => {
+ v.visit_lit_byte_mut(_binding_0);
+ }
+ Lit::Char(_binding_0) => {
+ v.visit_lit_char_mut(_binding_0);
+ }
+ Lit::Int(_binding_0) => {
+ v.visit_lit_int_mut(_binding_0);
+ }
+ Lit::Float(_binding_0) => {
+ v.visit_lit_float_mut(_binding_0);
+ }
+ Lit::Bool(_binding_0) => {
+ v.visit_lit_bool_mut(_binding_0);
+ }
+ Lit::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_bool_mut<V>(v: &mut V, node: &mut LitBool)
+where
+ V: VisitMut + ?Sized,
+{
+ skip!(node.value);
+ v.visit_span_mut(&mut node.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_byte_mut<V>(v: &mut V, node: &mut LitByte)
+where
+ V: VisitMut + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_byte_str_mut<V>(v: &mut V, node: &mut LitByteStr)
+where
+ V: VisitMut + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_char_mut<V>(v: &mut V, node: &mut LitChar)
+where
+ V: VisitMut + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_float_mut<V>(v: &mut V, node: &mut LitFloat)
+where
+ V: VisitMut + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_int_mut<V>(v: &mut V, node: &mut LitInt)
+where
+ V: VisitMut + ?Sized,
+{
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_lit_str_mut<V>(v: &mut V, node: &mut LitStr)
+where
+ V: VisitMut + ?Sized,
+{
+}
+#[cfg(feature = "full")]
+pub fn visit_local_mut<V>(v: &mut V, node: &mut Local)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.let_token.span);
+ v.visit_pat_mut(&mut node.pat);
+ if let Some(it) = &mut node.init {
+ tokens_helper(v, &mut (it).0.spans);
+ v.visit_expr_mut(&mut *(it).1);
+ };
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_macro_mut<V>(v: &mut V, node: &mut Macro)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_path_mut(&mut node.path);
+ tokens_helper(v, &mut node.bang_token.spans);
+ v.visit_macro_delimiter_mut(&mut node.delimiter);
+ skip!(node.tokens);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_macro_delimiter_mut<V>(v: &mut V, node: &mut MacroDelimiter)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ MacroDelimiter::Paren(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.span);
+ }
+ MacroDelimiter::Brace(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.span);
+ }
+ MacroDelimiter::Bracket(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.span);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_member_mut<V>(v: &mut V, node: &mut Member)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Member::Named(_binding_0) => {
+ v.visit_ident_mut(_binding_0);
+ }
+ Member::Unnamed(_binding_0) => {
+ v.visit_index_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_meta_mut<V>(v: &mut V, node: &mut Meta)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Meta::Path(_binding_0) => {
+ v.visit_path_mut(_binding_0);
+ }
+ Meta::List(_binding_0) => {
+ v.visit_meta_list_mut(_binding_0);
+ }
+ Meta::NameValue(_binding_0) => {
+ v.visit_meta_name_value_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_meta_list_mut<V>(v: &mut V, node: &mut MetaList)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_path_mut(&mut node.path);
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.nested) {
+ let (it, p) = el.into_tuple();
+ v.visit_nested_meta_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_meta_name_value_mut<V>(v: &mut V, node: &mut MetaNameValue)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_path_mut(&mut node.path);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_lit_mut(&mut node.lit);
+}
+#[cfg(feature = "full")]
+pub fn visit_method_turbofish_mut<V>(v: &mut V, node: &mut MethodTurbofish)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.colon2_token.spans);
+ tokens_helper(v, &mut node.lt_token.spans);
+ for el in Punctuated::pairs_mut(&mut node.args) {
+ let (it, p) = el.into_tuple();
+ v.visit_generic_method_argument_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ tokens_helper(v, &mut node.gt_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_nested_meta_mut<V>(v: &mut V, node: &mut NestedMeta)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ NestedMeta::Meta(_binding_0) => {
+ v.visit_meta_mut(_binding_0);
+ }
+ NestedMeta::Lit(_binding_0) => {
+ v.visit_lit_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_parenthesized_generic_arguments_mut<V>(
+ v: &mut V,
+ node: &mut ParenthesizedGenericArguments,
+) where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.inputs) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ v.visit_return_type_mut(&mut node.output);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_mut<V>(v: &mut V, node: &mut Pat)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Pat::Box(_binding_0) => {
+ v.visit_pat_box_mut(_binding_0);
+ }
+ Pat::Ident(_binding_0) => {
+ v.visit_pat_ident_mut(_binding_0);
+ }
+ Pat::Lit(_binding_0) => {
+ v.visit_pat_lit_mut(_binding_0);
+ }
+ Pat::Macro(_binding_0) => {
+ v.visit_pat_macro_mut(_binding_0);
+ }
+ Pat::Or(_binding_0) => {
+ v.visit_pat_or_mut(_binding_0);
+ }
+ Pat::Path(_binding_0) => {
+ v.visit_pat_path_mut(_binding_0);
+ }
+ Pat::Range(_binding_0) => {
+ v.visit_pat_range_mut(_binding_0);
+ }
+ Pat::Reference(_binding_0) => {
+ v.visit_pat_reference_mut(_binding_0);
+ }
+ Pat::Rest(_binding_0) => {
+ v.visit_pat_rest_mut(_binding_0);
+ }
+ Pat::Slice(_binding_0) => {
+ v.visit_pat_slice_mut(_binding_0);
+ }
+ Pat::Struct(_binding_0) => {
+ v.visit_pat_struct_mut(_binding_0);
+ }
+ Pat::Tuple(_binding_0) => {
+ v.visit_pat_tuple_mut(_binding_0);
+ }
+ Pat::TupleStruct(_binding_0) => {
+ v.visit_pat_tuple_struct_mut(_binding_0);
+ }
+ Pat::Type(_binding_0) => {
+ v.visit_pat_type_mut(_binding_0);
+ }
+ Pat::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ Pat::Wild(_binding_0) => {
+ v.visit_pat_wild_mut(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_box_mut<V>(v: &mut V, node: &mut PatBox)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.box_token.span);
+ v.visit_pat_mut(&mut *node.pat);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_ident_mut<V>(v: &mut V, node: &mut PatIdent)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.by_ref {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.mutability {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_ident_mut(&mut node.ident);
+ if let Some(it) = &mut node.subpat {
+ tokens_helper(v, &mut (it).0.spans);
+ v.visit_pat_mut(&mut *(it).1);
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_lit_mut<V>(v: &mut V, node: &mut PatLit)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.expr);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_macro_mut<V>(v: &mut V, node: &mut PatMacro)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_macro_mut(&mut node.mac);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_or_mut<V>(v: &mut V, node: &mut PatOr)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.leading_vert {
+ tokens_helper(v, &mut it.spans)
+ };
+ for el in Punctuated::pairs_mut(&mut node.cases) {
+ let (it, p) = el.into_tuple();
+ v.visit_pat_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_path_mut<V>(v: &mut V, node: &mut PatPath)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.qself {
+ v.visit_qself_mut(it)
+ };
+ v.visit_path_mut(&mut node.path);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_range_mut<V>(v: &mut V, node: &mut PatRange)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_expr_mut(&mut *node.lo);
+ v.visit_range_limits_mut(&mut node.limits);
+ v.visit_expr_mut(&mut *node.hi);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_reference_mut<V>(v: &mut V, node: &mut PatReference)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.and_token.spans);
+ if let Some(it) = &mut node.mutability {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_pat_mut(&mut *node.pat);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_rest_mut<V>(v: &mut V, node: &mut PatRest)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.dot2_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_slice_mut<V>(v: &mut V, node: &mut PatSlice)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.bracket_token.span);
+ for el in Punctuated::pairs_mut(&mut node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_pat_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_struct_mut<V>(v: &mut V, node: &mut PatStruct)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_path_mut(&mut node.path);
+ tokens_helper(v, &mut node.brace_token.span);
+ for el in Punctuated::pairs_mut(&mut node.fields) {
+ let (it, p) = el.into_tuple();
+ v.visit_field_pat_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ if let Some(it) = &mut node.dot2_token {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_tuple_mut<V>(v: &mut V, node: &mut PatTuple)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_pat_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_tuple_struct_mut<V>(v: &mut V, node: &mut PatTupleStruct)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_path_mut(&mut node.path);
+ v.visit_pat_tuple_mut(&mut node.pat);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_type_mut<V>(v: &mut V, node: &mut PatType)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_pat_mut(&mut *node.pat);
+ tokens_helper(v, &mut node.colon_token.spans);
+ v.visit_type_mut(&mut *node.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_pat_wild_mut<V>(v: &mut V, node: &mut PatWild)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.underscore_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_path_mut<V>(v: &mut V, node: &mut Path)
+where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.leading_colon {
+ tokens_helper(v, &mut it.spans)
+ };
+ for el in Punctuated::pairs_mut(&mut node.segments) {
+ let (it, p) = el.into_tuple();
+ v.visit_path_segment_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_path_arguments_mut<V>(v: &mut V, node: &mut PathArguments)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(_binding_0) => {
+ v.visit_angle_bracketed_generic_arguments_mut(_binding_0);
+ }
+ PathArguments::Parenthesized(_binding_0) => {
+ v.visit_parenthesized_generic_arguments_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_path_segment_mut<V>(v: &mut V, node: &mut PathSegment)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_path_arguments_mut(&mut node.arguments);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_predicate_eq_mut<V>(v: &mut V, node: &mut PredicateEq)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_type_mut(&mut node.lhs_ty);
+ tokens_helper(v, &mut node.eq_token.spans);
+ v.visit_type_mut(&mut node.rhs_ty);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_predicate_lifetime_mut<V>(v: &mut V, node: &mut PredicateLifetime)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_lifetime_mut(&mut node.lifetime);
+ tokens_helper(v, &mut node.colon_token.spans);
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_lifetime_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_predicate_type_mut<V>(v: &mut V, node: &mut PredicateType)
+where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.lifetimes {
+ v.visit_bound_lifetimes_mut(it)
+ };
+ v.visit_type_mut(&mut node.bounded_ty);
+ tokens_helper(v, &mut node.colon_token.spans);
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_qself_mut<V>(v: &mut V, node: &mut QSelf)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.lt_token.spans);
+ v.visit_type_mut(&mut *node.ty);
+ skip!(node.position);
+ if let Some(it) = &mut node.as_token {
+ tokens_helper(v, &mut it.span)
+ };
+ tokens_helper(v, &mut node.gt_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_range_limits_mut<V>(v: &mut V, node: &mut RangeLimits)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ RangeLimits::HalfOpen(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ RangeLimits::Closed(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_receiver_mut<V>(v: &mut V, node: &mut Receiver)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ if let Some(it) = &mut node.reference {
+ tokens_helper(v, &mut (it).0.spans);
+ if let Some(it) = &mut (it).1 {
+ v.visit_lifetime_mut(it)
+ };
+ };
+ if let Some(it) = &mut node.mutability {
+ tokens_helper(v, &mut it.span)
+ };
+ tokens_helper(v, &mut node.self_token.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_return_type_mut<V>(v: &mut V, node: &mut ReturnType)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ ReturnType::Default => {}
+ ReturnType::Type(_binding_0, _binding_1) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ v.visit_type_mut(&mut **_binding_1);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_signature_mut<V>(v: &mut V, node: &mut Signature)
+where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.constness {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.asyncness {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.unsafety {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.abi {
+ v.visit_abi_mut(it)
+ };
+ tokens_helper(v, &mut node.fn_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.inputs) {
+ let (it, p) = el.into_tuple();
+ v.visit_fn_arg_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ if let Some(it) = &mut node.variadic {
+ v.visit_variadic_mut(it)
+ };
+ v.visit_return_type_mut(&mut node.output);
+}
+pub fn visit_span_mut<V>(v: &mut V, node: &mut Span)
+where
+ V: VisitMut + ?Sized,
+{
+}
+#[cfg(feature = "full")]
+pub fn visit_stmt_mut<V>(v: &mut V, node: &mut Stmt)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Stmt::Local(_binding_0) => {
+ v.visit_local_mut(_binding_0);
+ }
+ Stmt::Item(_binding_0) => {
+ v.visit_item_mut(_binding_0);
+ }
+ Stmt::Expr(_binding_0) => {
+ v.visit_expr_mut(_binding_0);
+ }
+ Stmt::Semi(_binding_0, _binding_1) => {
+ v.visit_expr_mut(_binding_0);
+ tokens_helper(v, &mut _binding_1.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_trait_bound_mut<V>(v: &mut V, node: &mut TraitBound)
+where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.paren_token {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_trait_bound_modifier_mut(&mut node.modifier);
+ if let Some(it) = &mut node.lifetimes {
+ v.visit_bound_lifetimes_mut(it)
+ };
+ v.visit_path_mut(&mut node.path);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_trait_bound_modifier_mut<V>(v: &mut V, node: &mut TraitBoundModifier)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ TraitBoundModifier::None => {}
+ TraitBoundModifier::Maybe(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_mut<V>(v: &mut V, node: &mut TraitItem)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ TraitItem::Const(_binding_0) => {
+ v.visit_trait_item_const_mut(_binding_0);
+ }
+ TraitItem::Method(_binding_0) => {
+ v.visit_trait_item_method_mut(_binding_0);
+ }
+ TraitItem::Type(_binding_0) => {
+ v.visit_trait_item_type_mut(_binding_0);
+ }
+ TraitItem::Macro(_binding_0) => {
+ v.visit_trait_item_macro_mut(_binding_0);
+ }
+ TraitItem::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_const_mut<V>(v: &mut V, node: &mut TraitItemConst)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.const_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.colon_token.spans);
+ v.visit_type_mut(&mut node.ty);
+ if let Some(it) = &mut node.default {
+ tokens_helper(v, &mut (it).0.spans);
+ v.visit_expr_mut(&mut (it).1);
+ };
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_macro_mut<V>(v: &mut V, node: &mut TraitItemMacro)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_macro_mut(&mut node.mac);
+ if let Some(it) = &mut node.semi_token {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_method_mut<V>(v: &mut V, node: &mut TraitItemMethod)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_signature_mut(&mut node.sig);
+ if let Some(it) = &mut node.default {
+ v.visit_block_mut(it)
+ };
+ if let Some(it) = &mut node.semi_token {
+ tokens_helper(v, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_type_mut<V>(v: &mut V, node: &mut TraitItemType)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.type_token.span);
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_generics_mut(&mut node.generics);
+ if let Some(it) = &mut node.colon_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ if let Some(it) = &mut node.default {
+ tokens_helper(v, &mut (it).0.spans);
+ v.visit_type_mut(&mut (it).1);
+ };
+ tokens_helper(v, &mut node.semi_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_mut<V>(v: &mut V, node: &mut Type)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Type::Array(_binding_0) => {
+ v.visit_type_array_mut(_binding_0);
+ }
+ Type::BareFn(_binding_0) => {
+ v.visit_type_bare_fn_mut(_binding_0);
+ }
+ Type::Group(_binding_0) => {
+ v.visit_type_group_mut(_binding_0);
+ }
+ Type::ImplTrait(_binding_0) => {
+ v.visit_type_impl_trait_mut(_binding_0);
+ }
+ Type::Infer(_binding_0) => {
+ v.visit_type_infer_mut(_binding_0);
+ }
+ Type::Macro(_binding_0) => {
+ v.visit_type_macro_mut(_binding_0);
+ }
+ Type::Never(_binding_0) => {
+ v.visit_type_never_mut(_binding_0);
+ }
+ Type::Paren(_binding_0) => {
+ v.visit_type_paren_mut(_binding_0);
+ }
+ Type::Path(_binding_0) => {
+ v.visit_type_path_mut(_binding_0);
+ }
+ Type::Ptr(_binding_0) => {
+ v.visit_type_ptr_mut(_binding_0);
+ }
+ Type::Reference(_binding_0) => {
+ v.visit_type_reference_mut(_binding_0);
+ }
+ Type::Slice(_binding_0) => {
+ v.visit_type_slice_mut(_binding_0);
+ }
+ Type::TraitObject(_binding_0) => {
+ v.visit_type_trait_object_mut(_binding_0);
+ }
+ Type::Tuple(_binding_0) => {
+ v.visit_type_tuple_mut(_binding_0);
+ }
+ Type::Verbatim(_binding_0) => {
+ skip!(_binding_0);
+ }
+ _ => unreachable!(),
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_array_mut<V>(v: &mut V, node: &mut TypeArray)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.bracket_token.span);
+ v.visit_type_mut(&mut *node.elem);
+ tokens_helper(v, &mut node.semi_token.spans);
+ v.visit_expr_mut(&mut node.len);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_bare_fn_mut<V>(v: &mut V, node: &mut TypeBareFn)
+where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.lifetimes {
+ v.visit_bound_lifetimes_mut(it)
+ };
+ if let Some(it) = &mut node.unsafety {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.abi {
+ v.visit_abi_mut(it)
+ };
+ tokens_helper(v, &mut node.fn_token.span);
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.inputs) {
+ let (it, p) = el.into_tuple();
+ v.visit_bare_fn_arg_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ if let Some(it) = &mut node.variadic {
+ v.visit_variadic_mut(it)
+ };
+ v.visit_return_type_mut(&mut node.output);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_group_mut<V>(v: &mut V, node: &mut TypeGroup)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.group_token.span);
+ v.visit_type_mut(&mut *node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_impl_trait_mut<V>(v: &mut V, node: &mut TypeImplTrait)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.impl_token.span);
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_infer_mut<V>(v: &mut V, node: &mut TypeInfer)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.underscore_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_macro_mut<V>(v: &mut V, node: &mut TypeMacro)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_macro_mut(&mut node.mac);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_never_mut<V>(v: &mut V, node: &mut TypeNever)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.bang_token.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_param_mut<V>(v: &mut V, node: &mut TypeParam)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_ident_mut(&mut node.ident);
+ if let Some(it) = &mut node.colon_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+ if let Some(it) = &mut node.eq_token {
+ tokens_helper(v, &mut it.spans)
+ };
+ if let Some(it) = &mut node.default {
+ v.visit_type_mut(it)
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_param_bound_mut<V>(v: &mut V, node: &mut TypeParamBound)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ TypeParamBound::Trait(_binding_0) => {
+ v.visit_trait_bound_mut(_binding_0);
+ }
+ TypeParamBound::Lifetime(_binding_0) => {
+ v.visit_lifetime_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_paren_mut<V>(v: &mut V, node: &mut TypeParen)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.paren_token.span);
+ v.visit_type_mut(&mut *node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_path_mut<V>(v: &mut V, node: &mut TypePath)
+where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.qself {
+ v.visit_qself_mut(it)
+ };
+ v.visit_path_mut(&mut node.path);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_ptr_mut<V>(v: &mut V, node: &mut TypePtr)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.star_token.spans);
+ if let Some(it) = &mut node.const_token {
+ tokens_helper(v, &mut it.span)
+ };
+ if let Some(it) = &mut node.mutability {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_type_mut(&mut *node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_reference_mut<V>(v: &mut V, node: &mut TypeReference)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.and_token.spans);
+ if let Some(it) = &mut node.lifetime {
+ v.visit_lifetime_mut(it)
+ };
+ if let Some(it) = &mut node.mutability {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_type_mut(&mut *node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_slice_mut<V>(v: &mut V, node: &mut TypeSlice)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.bracket_token.span);
+ v.visit_type_mut(&mut *node.elem);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_trait_object_mut<V>(v: &mut V, node: &mut TypeTraitObject)
+where
+ V: VisitMut + ?Sized,
+{
+ if let Some(it) = &mut node.dyn_token {
+ tokens_helper(v, &mut it.span)
+ };
+ for el in Punctuated::pairs_mut(&mut node.bounds) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_param_bound_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_type_tuple_mut<V>(v: &mut V, node: &mut TypeTuple)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.paren_token.span);
+ for el in Punctuated::pairs_mut(&mut node.elems) {
+ let (it, p) = el.into_tuple();
+ v.visit_type_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_un_op_mut<V>(v: &mut V, node: &mut UnOp)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ UnOp::Deref(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ UnOp::Not(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ UnOp::Neg(_binding_0) => {
+ tokens_helper(v, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_use_glob_mut<V>(v: &mut V, node: &mut UseGlob)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.star_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_group_mut<V>(v: &mut V, node: &mut UseGroup)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.brace_token.span);
+ for el in Punctuated::pairs_mut(&mut node.items) {
+ let (it, p) = el.into_tuple();
+ v.visit_use_tree_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_use_name_mut<V>(v: &mut V, node: &mut UseName)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_ident_mut(&mut node.ident);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_path_mut<V>(v: &mut V, node: &mut UsePath)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.colon2_token.spans);
+ v.visit_use_tree_mut(&mut *node.tree);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_rename_mut<V>(v: &mut V, node: &mut UseRename)
+where
+ V: VisitMut + ?Sized,
+{
+ v.visit_ident_mut(&mut node.ident);
+ tokens_helper(v, &mut node.as_token.span);
+ v.visit_ident_mut(&mut node.rename);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_tree_mut<V>(v: &mut V, node: &mut UseTree)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ UseTree::Path(_binding_0) => {
+ v.visit_use_path_mut(_binding_0);
+ }
+ UseTree::Name(_binding_0) => {
+ v.visit_use_name_mut(_binding_0);
+ }
+ UseTree::Rename(_binding_0) => {
+ v.visit_use_rename_mut(_binding_0);
+ }
+ UseTree::Glob(_binding_0) => {
+ v.visit_use_glob_mut(_binding_0);
+ }
+ UseTree::Group(_binding_0) => {
+ v.visit_use_group_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_variadic_mut<V>(v: &mut V, node: &mut Variadic)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ tokens_helper(v, &mut node.dots.spans);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_variant_mut<V>(v: &mut V, node: &mut Variant)
+where
+ V: VisitMut + ?Sized,
+{
+ for it in &mut node.attrs {
+ v.visit_attribute_mut(it)
+ }
+ v.visit_ident_mut(&mut node.ident);
+ v.visit_fields_mut(&mut node.fields);
+ if let Some(it) = &mut node.discriminant {
+ tokens_helper(v, &mut (it).0.spans);
+ v.visit_expr_mut(&mut (it).1);
+ };
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_vis_crate_mut<V>(v: &mut V, node: &mut VisCrate)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.crate_token.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_vis_public_mut<V>(v: &mut V, node: &mut VisPublic)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.pub_token.span);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_vis_restricted_mut<V>(v: &mut V, node: &mut VisRestricted)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.pub_token.span);
+ tokens_helper(v, &mut node.paren_token.span);
+ if let Some(it) = &mut node.in_token {
+ tokens_helper(v, &mut it.span)
+ };
+ v.visit_path_mut(&mut *node.path);
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_visibility_mut<V>(v: &mut V, node: &mut Visibility)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ Visibility::Public(_binding_0) => {
+ v.visit_vis_public_mut(_binding_0);
+ }
+ Visibility::Crate(_binding_0) => {
+ v.visit_vis_crate_mut(_binding_0);
+ }
+ Visibility::Restricted(_binding_0) => {
+ v.visit_vis_restricted_mut(_binding_0);
+ }
+ Visibility::Inherited => {}
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_where_clause_mut<V>(v: &mut V, node: &mut WhereClause)
+where
+ V: VisitMut + ?Sized,
+{
+ tokens_helper(v, &mut node.where_token.span);
+ for el in Punctuated::pairs_mut(&mut node.predicates) {
+ let (it, p) = el.into_tuple();
+ v.visit_where_predicate_mut(it);
+ if let Some(p) = p {
+ tokens_helper(v, &mut p.spans);
+ }
+ }
+}
+#[cfg(any(feature = "derive", feature = "full"))]
+pub fn visit_where_predicate_mut<V>(v: &mut V, node: &mut WherePredicate)
+where
+ V: VisitMut + ?Sized,
+{
+ match node {
+ WherePredicate::Type(_binding_0) => {
+ v.visit_predicate_type_mut(_binding_0);
+ }
+ WherePredicate::Lifetime(_binding_0) => {
+ v.visit_predicate_lifetime_mut(_binding_0);
+ }
+ WherePredicate::Eq(_binding_0) => {
+ v.visit_predicate_eq_mut(_binding_0);
+ }
+ }
+}
diff --git a/syn/src/gen_helper.rs b/syn/src/gen_helper.rs
new file mode 100644
index 0000000..b279612
--- /dev/null
+++ b/syn/src/gen_helper.rs
@@ -0,0 +1,154 @@
+#[cfg(feature = "fold")]
+pub mod fold {
+ use crate::fold::Fold;
+ use crate::punctuated::{Pair, Punctuated};
+ use proc_macro2::Span;
+
+ pub trait FoldHelper {
+ type Item;
+ fn lift<F>(self, f: F) -> Self
+ where
+ F: FnMut(Self::Item) -> Self::Item;
+ }
+
+ impl<T> FoldHelper for Vec<T> {
+ type Item = T;
+ fn lift<F>(self, f: F) -> Self
+ where
+ F: FnMut(Self::Item) -> Self::Item,
+ {
+ self.into_iter().map(f).collect()
+ }
+ }
+
+ impl<T, U> FoldHelper for Punctuated<T, U> {
+ type Item = T;
+ fn lift<F>(self, mut f: F) -> Self
+ where
+ F: FnMut(Self::Item) -> Self::Item,
+ {
+ self.into_pairs()
+ .map(Pair::into_tuple)
+ .map(|(t, u)| Pair::new(f(t), u))
+ .collect()
+ }
+ }
+
+ pub fn tokens_helper<F: Fold + ?Sized, S: Spans>(folder: &mut F, spans: &S) -> S {
+ spans.fold(folder)
+ }
+
+ pub trait Spans {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self;
+ }
+
+ impl Spans for Span {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self {
+ folder.fold_span(*self)
+ }
+ }
+
+ impl Spans for [Span; 1] {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self {
+ [folder.fold_span(self[0])]
+ }
+ }
+
+ impl Spans for [Span; 2] {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self {
+ [folder.fold_span(self[0]), folder.fold_span(self[1])]
+ }
+ }
+
+ impl Spans for [Span; 3] {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self {
+ [
+ folder.fold_span(self[0]),
+ folder.fold_span(self[1]),
+ folder.fold_span(self[2]),
+ ]
+ }
+ }
+}
+
+#[cfg(feature = "visit")]
+pub mod visit {
+ use crate::visit::Visit;
+ use proc_macro2::Span;
+
+ pub fn tokens_helper<'ast, V: Visit<'ast> + ?Sized, S: Spans>(visitor: &mut V, spans: &S) {
+ spans.visit(visitor);
+ }
+
+ pub trait Spans {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&self, visitor: &mut V);
+ }
+
+ impl Spans for Span {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&self, visitor: &mut V) {
+ visitor.visit_span(self);
+ }
+ }
+
+ impl Spans for [Span; 1] {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&self, visitor: &mut V) {
+ visitor.visit_span(&self[0]);
+ }
+ }
+
+ impl Spans for [Span; 2] {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&self, visitor: &mut V) {
+ visitor.visit_span(&self[0]);
+ visitor.visit_span(&self[1]);
+ }
+ }
+
+ impl Spans for [Span; 3] {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&self, visitor: &mut V) {
+ visitor.visit_span(&self[0]);
+ visitor.visit_span(&self[1]);
+ visitor.visit_span(&self[2]);
+ }
+ }
+}
+
+#[cfg(feature = "visit-mut")]
+pub mod visit_mut {
+ use crate::visit_mut::VisitMut;
+ use proc_macro2::Span;
+
+ pub fn tokens_helper<V: VisitMut + ?Sized, S: Spans>(visitor: &mut V, spans: &mut S) {
+ spans.visit_mut(visitor);
+ }
+
+ pub trait Spans {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V);
+ }
+
+ impl Spans for Span {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) {
+ visitor.visit_span_mut(self);
+ }
+ }
+
+ impl Spans for [Span; 1] {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) {
+ visitor.visit_span_mut(&mut self[0]);
+ }
+ }
+
+ impl Spans for [Span; 2] {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) {
+ visitor.visit_span_mut(&mut self[0]);
+ visitor.visit_span_mut(&mut self[1]);
+ }
+ }
+
+ impl Spans for [Span; 3] {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) {
+ visitor.visit_span_mut(&mut self[0]);
+ visitor.visit_span_mut(&mut self[1]);
+ visitor.visit_span_mut(&mut self[2]);
+ }
+ }
+}
diff --git a/syn/src/generics.rs b/syn/src/generics.rs
new file mode 100644
index 0000000..9feeab9
--- /dev/null
+++ b/syn/src/generics.rs
@@ -0,0 +1,1152 @@
+use super::*;
+use crate::punctuated::{Iter, IterMut, Punctuated};
+
+ast_struct! {
+ /// Lifetimes and type parameters attached to a declaration of a function,
+ /// enum, trait, etc.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[derive(Default)]
+ pub struct Generics {
+ pub lt_token: Option<Token![<]>,
+ pub params: Punctuated<GenericParam, Token![,]>,
+ pub gt_token: Option<Token![>]>,
+ pub where_clause: Option<WhereClause>,
+ }
+}
+
+ast_enum_of_structs! {
+ /// A generic type parameter, lifetime, or const generic: `T: Into<String>`,
+ /// `'a: 'b`, `const LEN: usize`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum GenericParam {
+ /// A generic type parameter: `T: Into<String>`.
+ Type(TypeParam),
+
+ /// A lifetime definition: `'a: 'b + 'c + 'd`.
+ Lifetime(LifetimeDef),
+
+ /// A const generic parameter: `const LENGTH: usize`.
+ Const(ConstParam),
+ }
+}
+
+ast_struct! {
+ /// A generic type parameter: `T: Into<String>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeParam {
+ pub attrs: Vec<Attribute>,
+ pub ident: Ident,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ pub eq_token: Option<Token![=]>,
+ pub default: Option<Type>,
+ }
+}
+
+ast_struct! {
+ /// A lifetime definition: `'a: 'b + 'c + 'd`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct LifetimeDef {
+ pub attrs: Vec<Attribute>,
+ pub lifetime: Lifetime,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<Lifetime, Token![+]>,
+ }
+}
+
+ast_struct! {
+ /// A const generic parameter: `const LENGTH: usize`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct ConstParam {
+ pub attrs: Vec<Attribute>,
+ pub const_token: Token![const],
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Type,
+ pub eq_token: Option<Token![=]>,
+ pub default: Option<Expr>,
+ }
+}
+
+impl Generics {
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator&lt;Item = &amp;</code><a
+ /// href="struct.TypeParam.html"><code
+ /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code
+ /// style="padding-left:0;">&gt;</code>
+ /// over the type parameters in `self.params`.
+ pub fn type_params(&self) -> TypeParams {
+ TypeParams(self.params.iter())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator&lt;Item = &amp;mut </code><a
+ /// href="struct.TypeParam.html"><code
+ /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code
+ /// style="padding-left:0;">&gt;</code>
+ /// over the type parameters in `self.params`.
+ pub fn type_params_mut(&mut self) -> TypeParamsMut {
+ TypeParamsMut(self.params.iter_mut())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator&lt;Item = &amp;</code><a
+ /// href="struct.LifetimeDef.html"><code
+ /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code
+ /// style="padding-left:0;">&gt;</code>
+ /// over the lifetime parameters in `self.params`.
+ pub fn lifetimes(&self) -> Lifetimes {
+ Lifetimes(self.params.iter())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator&lt;Item = &amp;mut </code><a
+ /// href="struct.LifetimeDef.html"><code
+ /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code
+ /// style="padding-left:0;">&gt;</code>
+ /// over the lifetime parameters in `self.params`.
+ pub fn lifetimes_mut(&mut self) -> LifetimesMut {
+ LifetimesMut(self.params.iter_mut())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator&lt;Item = &amp;</code><a
+ /// href="struct.ConstParam.html"><code
+ /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code
+ /// style="padding-left:0;">&gt;</code>
+ /// over the constant parameters in `self.params`.
+ pub fn const_params(&self) -> ConstParams {
+ ConstParams(self.params.iter())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator&lt;Item = &amp;mut </code><a
+ /// href="struct.ConstParam.html"><code
+ /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code
+ /// style="padding-left:0;">&gt;</code>
+ /// over the constant parameters in `self.params`.
+ pub fn const_params_mut(&mut self) -> ConstParamsMut {
+ ConstParamsMut(self.params.iter_mut())
+ }
+
+ /// Initializes an empty `where`-clause if there is not one present already.
+ pub fn make_where_clause(&mut self) -> &mut WhereClause {
+ // This is Option::get_or_insert_with in Rust 1.20.
+ if self.where_clause.is_none() {
+ self.where_clause = Some(WhereClause {
+ where_token: <Token![where]>::default(),
+ predicates: Punctuated::new(),
+ });
+ }
+ match &mut self.where_clause {
+ Some(where_clause) => where_clause,
+ None => unreachable!(),
+ }
+ }
+}
+
+pub struct TypeParams<'a>(Iter<'a, GenericParam>);
+
+impl<'a> Iterator for TypeParams<'a> {
+ type Item = &'a TypeParam;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Type(type_param) = next {
+ Some(type_param)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct TypeParamsMut<'a>(IterMut<'a, GenericParam>);
+
+impl<'a> Iterator for TypeParamsMut<'a> {
+ type Item = &'a mut TypeParam;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Type(type_param) = next {
+ Some(type_param)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct Lifetimes<'a>(Iter<'a, GenericParam>);
+
+impl<'a> Iterator for Lifetimes<'a> {
+ type Item = &'a LifetimeDef;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Lifetime(lifetime) = next {
+ Some(lifetime)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct LifetimesMut<'a>(IterMut<'a, GenericParam>);
+
+impl<'a> Iterator for LifetimesMut<'a> {
+ type Item = &'a mut LifetimeDef;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Lifetime(lifetime) = next {
+ Some(lifetime)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct ConstParams<'a>(Iter<'a, GenericParam>);
+
+impl<'a> Iterator for ConstParams<'a> {
+ type Item = &'a ConstParam;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Const(const_param) = next {
+ Some(const_param)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct ConstParamsMut<'a>(IterMut<'a, GenericParam>);
+
+impl<'a> Iterator for ConstParamsMut<'a> {
+ type Item = &'a mut ConstParam;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Const(const_param) = next {
+ Some(const_param)
+ } else {
+ self.next()
+ }
+ }
+}
+
+/// Returned by `Generics::split_for_impl`.
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature and the `"printing"` feature.*
+#[cfg(feature = "printing")]
+#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct ImplGenerics<'a>(&'a Generics);
+
+/// Returned by `Generics::split_for_impl`.
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature and the `"printing"` feature.*
+#[cfg(feature = "printing")]
+#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct TypeGenerics<'a>(&'a Generics);
+
+/// Returned by `TypeGenerics::as_turbofish`.
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature and the `"printing"` feature.*
+#[cfg(feature = "printing")]
+#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct Turbofish<'a>(&'a Generics);
+
+#[cfg(feature = "printing")]
+impl Generics {
+ /// Split a type's generics into the pieces required for impl'ing a trait
+ /// for that type.
+ ///
+ /// ```
+ /// # use proc_macro2::{Span, Ident};
+ /// # use quote::quote;
+ /// #
+ /// # let generics: syn::Generics = Default::default();
+ /// # let name = Ident::new("MyType", Span::call_site());
+ /// #
+ /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+ /// quote! {
+ /// impl #impl_generics MyTrait for #name #ty_generics #where_clause {
+ /// // ...
+ /// }
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// *This method is available if Syn is built with the `"derive"` or
+ /// `"full"` feature and the `"printing"` feature.*
+ pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) {
+ (
+ ImplGenerics(self),
+ TypeGenerics(self),
+ self.where_clause.as_ref(),
+ )
+ }
+}
+
+#[cfg(feature = "printing")]
+impl<'a> TypeGenerics<'a> {
+ /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`.
+ ///
+ /// *This method is available if Syn is built with the `"derive"` or
+ /// `"full"` feature and the `"printing"` feature.*
+ pub fn as_turbofish(&self) -> Turbofish {
+ Turbofish(self.0)
+ }
+}
+
+ast_struct! {
+ /// A set of bound lifetimes: `for<'a, 'b, 'c>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[derive(Default)]
+ pub struct BoundLifetimes {
+ pub for_token: Token![for],
+ pub lt_token: Token![<],
+ pub lifetimes: Punctuated<LifetimeDef, Token![,]>,
+ pub gt_token: Token![>],
+ }
+}
+
+impl LifetimeDef {
+ pub fn new(lifetime: Lifetime) -> Self {
+ LifetimeDef {
+ attrs: Vec::new(),
+ lifetime,
+ colon_token: None,
+ bounds: Punctuated::new(),
+ }
+ }
+}
+
+impl From<Ident> for TypeParam {
+ fn from(ident: Ident) -> Self {
+ TypeParam {
+ attrs: vec![],
+ ident,
+ colon_token: None,
+ bounds: Punctuated::new(),
+ eq_token: None,
+ default: None,
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// A trait or lifetime used as a bound on a type parameter.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum TypeParamBound {
+ Trait(TraitBound),
+ Lifetime(Lifetime),
+ }
+}
+
+ast_struct! {
+ /// A trait used as a bound on a type parameter.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct TraitBound {
+ pub paren_token: Option<token::Paren>,
+ pub modifier: TraitBoundModifier,
+ /// The `for<'a>` in `for<'a> Foo<&'a T>`
+ pub lifetimes: Option<BoundLifetimes>,
+ /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`
+ pub path: Path,
+ }
+}
+
+ast_enum! {
+ /// A modifier on a trait bound, currently only used for the `?` in
+ /// `?Sized`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum TraitBoundModifier {
+ None,
+ Maybe(Token![?]),
+ }
+}
+
+ast_struct! {
+ /// A `where` clause in a definition: `where T: Deserialize<'de>, D:
+ /// 'static`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct WhereClause {
+ pub where_token: Token![where],
+ pub predicates: Punctuated<WherePredicate, Token![,]>,
+ }
+}
+
+ast_enum_of_structs! {
+ /// A single predicate in a `where` clause: `T: Deserialize<'de>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum WherePredicate {
+ /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
+ Type(PredicateType),
+
+ /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
+ Lifetime(PredicateLifetime),
+
+ /// An equality predicate in a `where` clause (unsupported).
+ Eq(PredicateEq),
+ }
+}
+
+ast_struct! {
+ /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct PredicateType {
+ /// Any lifetimes from a `for` binding
+ pub lifetimes: Option<BoundLifetimes>,
+ /// The type being bounded
+ pub bounded_ty: Type,
+ pub colon_token: Token![:],
+ /// Trait and lifetime bounds (`Clone+Send+'static`)
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ }
+}
+
+ast_struct! {
+ /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct PredicateLifetime {
+ pub lifetime: Lifetime,
+ pub colon_token: Token![:],
+ pub bounds: Punctuated<Lifetime, Token![+]>,
+ }
+}
+
+ast_struct! {
+ /// An equality predicate in a `where` clause (unsupported).
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct PredicateEq {
+ pub lhs_ty: Type,
+ pub eq_token: Token![=],
+ pub rhs_ty: Type,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::parse::{Parse, ParseStream, Result};
+
+ impl Parse for Generics {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if !input.peek(Token![<]) {
+ return Ok(Generics::default());
+ }
+
+ let lt_token: Token![<] = input.parse()?;
+
+ let mut params = Punctuated::new();
+ let mut allow_lifetime_param = true;
+ let mut allow_type_param = true;
+ loop {
+ if input.peek(Token![>]) {
+ break;
+ }
+
+ let attrs = input.call(Attribute::parse_outer)?;
+ let lookahead = input.lookahead1();
+ if allow_lifetime_param && lookahead.peek(Lifetime) {
+ params.push_value(GenericParam::Lifetime(LifetimeDef {
+ attrs,
+ ..input.parse()?
+ }));
+ } else if allow_type_param && lookahead.peek(Ident) {
+ allow_lifetime_param = false;
+ params.push_value(GenericParam::Type(TypeParam {
+ attrs,
+ ..input.parse()?
+ }));
+ } else if lookahead.peek(Token![const]) {
+ allow_lifetime_param = false;
+ allow_type_param = false;
+ params.push_value(GenericParam::Const(ConstParam {
+ attrs,
+ ..input.parse()?
+ }));
+ } else {
+ return Err(lookahead.error());
+ }
+
+ if input.peek(Token![>]) {
+ break;
+ }
+ let punct = input.parse()?;
+ params.push_punct(punct);
+ }
+
+ let gt_token: Token![>] = input.parse()?;
+
+ Ok(Generics {
+ lt_token: Some(lt_token),
+ params,
+ gt_token: Some(gt_token),
+ where_clause: None,
+ })
+ }
+ }
+
+ impl Parse for GenericParam {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Ident) {
+ Ok(GenericParam::Type(TypeParam {
+ attrs,
+ ..input.parse()?
+ }))
+ } else if lookahead.peek(Lifetime) {
+ Ok(GenericParam::Lifetime(LifetimeDef {
+ attrs,
+ ..input.parse()?
+ }))
+ } else if lookahead.peek(Token![const]) {
+ Ok(GenericParam::Const(ConstParam {
+ attrs,
+ ..input.parse()?
+ }))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ impl Parse for LifetimeDef {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let has_colon;
+ Ok(LifetimeDef {
+ attrs: input.call(Attribute::parse_outer)?,
+ lifetime: input.parse()?,
+ colon_token: {
+ if input.peek(Token![:]) {
+ has_colon = true;
+ Some(input.parse()?)
+ } else {
+ has_colon = false;
+ None
+ }
+ },
+ bounds: {
+ let mut bounds = Punctuated::new();
+ if has_colon {
+ loop {
+ if input.peek(Token![,]) || input.peek(Token![>]) {
+ break;
+ }
+ let value = input.parse()?;
+ bounds.push_value(value);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ let punct = input.parse()?;
+ bounds.push_punct(punct);
+ }
+ }
+ bounds
+ },
+ })
+ }
+ }
+
+ impl Parse for BoundLifetimes {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(BoundLifetimes {
+ for_token: input.parse()?,
+ lt_token: input.parse()?,
+ lifetimes: {
+ let mut lifetimes = Punctuated::new();
+ while !input.peek(Token![>]) {
+ lifetimes.push_value(input.parse()?);
+ if input.peek(Token![>]) {
+ break;
+ }
+ lifetimes.push_punct(input.parse()?);
+ }
+ lifetimes
+ },
+ gt_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for Option<BoundLifetimes> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Token![for]) {
+ input.parse().map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+ }
+
+ impl Parse for TypeParam {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let has_colon;
+ let has_default;
+ Ok(TypeParam {
+ attrs: input.call(Attribute::parse_outer)?,
+ ident: input.parse()?,
+ colon_token: {
+ if input.peek(Token![:]) {
+ has_colon = true;
+ Some(input.parse()?)
+ } else {
+ has_colon = false;
+ None
+ }
+ },
+ bounds: {
+ let mut bounds = Punctuated::new();
+ if has_colon {
+ loop {
+ if input.peek(Token![,])
+ || input.peek(Token![>])
+ || input.peek(Token![=])
+ {
+ break;
+ }
+ let value = input.parse()?;
+ bounds.push_value(value);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ let punct = input.parse()?;
+ bounds.push_punct(punct);
+ }
+ }
+ bounds
+ },
+ eq_token: {
+ if input.peek(Token![=]) {
+ has_default = true;
+ Some(input.parse()?)
+ } else {
+ has_default = false;
+ None
+ }
+ },
+ default: {
+ if has_default {
+ Some(input.parse()?)
+ } else {
+ None
+ }
+ },
+ })
+ }
+ }
+
+ impl Parse for TypeParamBound {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Lifetime) {
+ return input.parse().map(TypeParamBound::Lifetime);
+ }
+
+ if input.peek(token::Paren) {
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let mut bound: TraitBound = content.parse()?;
+ bound.paren_token = Some(paren_token);
+ return Ok(TypeParamBound::Trait(bound));
+ }
+
+ input.parse().map(TypeParamBound::Trait)
+ }
+ }
+
+ impl Parse for TraitBound {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let modifier: TraitBoundModifier = input.parse()?;
+ let lifetimes: Option<BoundLifetimes> = input.parse()?;
+
+ let mut path: Path = input.parse()?;
+ if path.segments.last().unwrap().arguments.is_empty() && input.peek(token::Paren) {
+ let parenthesized = PathArguments::Parenthesized(input.parse()?);
+ path.segments.last_mut().unwrap().arguments = parenthesized;
+ }
+
+ Ok(TraitBound {
+ paren_token: None,
+ modifier,
+ lifetimes,
+ path,
+ })
+ }
+ }
+
+ impl Parse for TraitBoundModifier {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Token![?]) {
+ input.parse().map(TraitBoundModifier::Maybe)
+ } else {
+ Ok(TraitBoundModifier::None)
+ }
+ }
+ }
+
+ impl Parse for ConstParam {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut default = None;
+ Ok(ConstParam {
+ attrs: input.call(Attribute::parse_outer)?,
+ const_token: input.parse()?,
+ ident: input.parse()?,
+ colon_token: input.parse()?,
+ ty: input.parse()?,
+ eq_token: {
+ if input.peek(Token![=]) {
+ let eq_token = input.parse()?;
+ default = Some(input.parse::<Expr>()?);
+ Some(eq_token)
+ } else {
+ None
+ }
+ },
+ default,
+ })
+ }
+ }
+
+ impl Parse for WhereClause {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(WhereClause {
+ where_token: input.parse()?,
+ predicates: {
+ let mut predicates = Punctuated::new();
+ loop {
+ if input.is_empty()
+ || input.peek(token::Brace)
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || input.peek(Token![:]) && !input.peek(Token![::])
+ || input.peek(Token![=])
+ {
+ break;
+ }
+ let value = input.parse()?;
+ predicates.push_value(value);
+ if !input.peek(Token![,]) {
+ break;
+ }
+ let punct = input.parse()?;
+ predicates.push_punct(punct);
+ }
+ predicates
+ },
+ })
+ }
+ }
+
+ impl Parse for Option<WhereClause> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Token![where]) {
+ input.parse().map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+ }
+
+ impl Parse for WherePredicate {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Lifetime) && input.peek2(Token![:]) {
+ Ok(WherePredicate::Lifetime(PredicateLifetime {
+ lifetime: input.parse()?,
+ colon_token: input.parse()?,
+ bounds: {
+ let mut bounds = Punctuated::new();
+ loop {
+ if input.is_empty()
+ || input.peek(token::Brace)
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || input.peek(Token![:])
+ || input.peek(Token![=])
+ {
+ break;
+ }
+ let value = input.parse()?;
+ bounds.push_value(value);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ let punct = input.parse()?;
+ bounds.push_punct(punct);
+ }
+ bounds
+ },
+ }))
+ } else {
+ Ok(WherePredicate::Type(PredicateType {
+ lifetimes: input.parse()?,
+ bounded_ty: input.parse()?,
+ colon_token: input.parse()?,
+ bounds: {
+ let mut bounds = Punctuated::new();
+ loop {
+ if input.is_empty()
+ || input.peek(token::Brace)
+ || input.peek(Token![,])
+ || input.peek(Token![;])
+ || input.peek(Token![:]) && !input.peek(Token![::])
+ || input.peek(Token![=])
+ {
+ break;
+ }
+ let value = input.parse()?;
+ bounds.push_value(value);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ let punct = input.parse()?;
+ bounds.push_punct(punct);
+ }
+ bounds
+ },
+ }))
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ use crate::attr::FilterAttrs;
+ use crate::print::TokensOrDefault;
+
+ impl ToTokens for Generics {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if self.params.is_empty() {
+ return;
+ }
+
+ TokensOrDefault(&self.lt_token).to_tokens(tokens);
+
+ // 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
+ let mut trailing_or_empty = true;
+ for param in self.params.pairs() {
+ if let GenericParam::Lifetime(_) = **param.value() {
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ }
+ for param in self.params.pairs() {
+ match **param.value() {
+ GenericParam::Type(_) | GenericParam::Const(_) => {
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ param.to_tokens(tokens);
+ }
+ GenericParam::Lifetime(_) => {}
+ }
+ }
+
+ TokensOrDefault(&self.gt_token).to_tokens(tokens);
+ }
+ }
+
+ impl<'a> ToTokens for ImplGenerics<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if self.0.params.is_empty() {
+ return;
+ }
+
+ TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
+
+ // 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
+ let mut trailing_or_empty = true;
+ for param in self.0.params.pairs() {
+ if let GenericParam::Lifetime(_) = **param.value() {
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ }
+ for param in self.0.params.pairs() {
+ if let GenericParam::Lifetime(_) = **param.value() {
+ continue;
+ }
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ match *param.value() {
+ GenericParam::Lifetime(_) => unreachable!(),
+ GenericParam::Type(param) => {
+ // Leave off the type parameter defaults
+ tokens.append_all(param.attrs.outer());
+ param.ident.to_tokens(tokens);
+ if !param.bounds.is_empty() {
+ TokensOrDefault(&param.colon_token).to_tokens(tokens);
+ param.bounds.to_tokens(tokens);
+ }
+ }
+ GenericParam::Const(param) => {
+ // Leave off the const parameter defaults
+ tokens.append_all(param.attrs.outer());
+ param.const_token.to_tokens(tokens);
+ param.ident.to_tokens(tokens);
+ param.colon_token.to_tokens(tokens);
+ param.ty.to_tokens(tokens);
+ }
+ }
+ param.punct().to_tokens(tokens);
+ }
+
+ TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
+ }
+ }
+
+ impl<'a> ToTokens for TypeGenerics<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if self.0.params.is_empty() {
+ return;
+ }
+
+ TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
+
+ // 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
+ let mut trailing_or_empty = true;
+ for param in self.0.params.pairs() {
+ if let GenericParam::Lifetime(def) = *param.value() {
+ // Leave off the lifetime bounds and attributes
+ def.lifetime.to_tokens(tokens);
+ param.punct().to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ }
+ for param in self.0.params.pairs() {
+ if let GenericParam::Lifetime(_) = **param.value() {
+ continue;
+ }
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ match *param.value() {
+ GenericParam::Lifetime(_) => unreachable!(),
+ GenericParam::Type(param) => {
+ // Leave off the type parameter defaults
+ param.ident.to_tokens(tokens);
+ }
+ GenericParam::Const(param) => {
+ // Leave off the const parameter defaults
+ param.ident.to_tokens(tokens);
+ }
+ }
+ param.punct().to_tokens(tokens);
+ }
+
+ TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
+ }
+ }
+
+ impl<'a> ToTokens for Turbofish<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.0.params.is_empty() {
+ <Token![::]>::default().to_tokens(tokens);
+ TypeGenerics(self.0).to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for BoundLifetimes {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.for_token.to_tokens(tokens);
+ self.lt_token.to_tokens(tokens);
+ self.lifetimes.to_tokens(tokens);
+ self.gt_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LifetimeDef {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.lifetime.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for TypeParam {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.ident.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ if self.default.is_some() {
+ TokensOrDefault(&self.eq_token).to_tokens(tokens);
+ self.default.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for TraitBound {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let to_tokens = |tokens: &mut TokenStream| {
+ self.modifier.to_tokens(tokens);
+ self.lifetimes.to_tokens(tokens);
+ self.path.to_tokens(tokens);
+ };
+ match &self.paren_token {
+ Some(paren) => paren.surround(tokens, to_tokens),
+ None => to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for TraitBoundModifier {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ TraitBoundModifier::None => {}
+ TraitBoundModifier::Maybe(t) => t.to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for ConstParam {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.const_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ if self.default.is_some() {
+ TokensOrDefault(&self.eq_token).to_tokens(tokens);
+ self.default.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for WhereClause {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.predicates.is_empty() {
+ self.where_token.to_tokens(tokens);
+ self.predicates.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for PredicateType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lifetimes.to_tokens(tokens);
+ self.bounded_ty.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PredicateLifetime {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lifetime.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PredicateEq {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lhs_ty.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.rhs_ty.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn/src/group.rs b/syn/src/group.rs
new file mode 100644
index 0000000..ed5b151
--- /dev/null
+++ b/syn/src/group.rs
@@ -0,0 +1,280 @@
+use proc_macro2::{Delimiter, Span};
+
+use crate::error::Result;
+use crate::parse::ParseBuffer;
+use crate::token;
+
+// Not public API.
+#[doc(hidden)]
+pub struct Parens<'a> {
+ pub token: token::Paren,
+ pub content: ParseBuffer<'a>,
+}
+
+// Not public API.
+#[doc(hidden)]
+pub struct Braces<'a> {
+ pub token: token::Brace,
+ pub content: ParseBuffer<'a>,
+}
+
+// Not public API.
+#[doc(hidden)]
+pub struct Brackets<'a> {
+ pub token: token::Bracket,
+ pub content: ParseBuffer<'a>,
+}
+
+// Not public API.
+#[cfg(any(feature = "full", feature = "derive"))]
+#[doc(hidden)]
+pub struct Group<'a> {
+ pub token: token::Group,
+ pub content: ParseBuffer<'a>,
+}
+
+// Not public API.
+#[doc(hidden)]
+pub fn parse_parens<'a>(input: &ParseBuffer<'a>) -> Result<Parens<'a>> {
+ parse_delimited(input, Delimiter::Parenthesis).map(|(span, content)| Parens {
+ token: token::Paren(span),
+ content,
+ })
+}
+
+// Not public API.
+#[doc(hidden)]
+pub fn parse_braces<'a>(input: &ParseBuffer<'a>) -> Result<Braces<'a>> {
+ parse_delimited(input, Delimiter::Brace).map(|(span, content)| Braces {
+ token: token::Brace(span),
+ content,
+ })
+}
+
+// Not public API.
+#[doc(hidden)]
+pub fn parse_brackets<'a>(input: &ParseBuffer<'a>) -> Result<Brackets<'a>> {
+ parse_delimited(input, Delimiter::Bracket).map(|(span, content)| Brackets {
+ token: token::Bracket(span),
+ content,
+ })
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+pub(crate) fn parse_group<'a>(input: &ParseBuffer<'a>) -> Result<Group<'a>> {
+ parse_delimited(input, Delimiter::None).map(|(span, content)| Group {
+ token: token::Group(span),
+ content,
+ })
+}
+
+fn parse_delimited<'a>(
+ input: &ParseBuffer<'a>,
+ delimiter: Delimiter,
+) -> Result<(Span, ParseBuffer<'a>)> {
+ input.step(|cursor| {
+ if let Some((content, span, rest)) = cursor.group(delimiter) {
+ let scope = crate::buffer::close_span_of_group(*cursor);
+ let nested = crate::parse::advance_step_cursor(cursor, content);
+ let unexpected = crate::parse::get_unexpected(input);
+ let content = crate::parse::new_parse_buffer(scope, nested, unexpected);
+ Ok(((span, content), rest))
+ } else {
+ let message = match delimiter {
+ Delimiter::Parenthesis => "expected parentheses",
+ Delimiter::Brace => "expected curly braces",
+ Delimiter::Bracket => "expected square brackets",
+ Delimiter::None => "expected invisible group",
+ };
+ Err(cursor.error(message))
+ }
+ })
+}
+
+/// Parse a set of parentheses and expose their content to subsequent parsers.
+///
+/// # Example
+///
+/// ```
+/// # use quote::quote;
+/// #
+/// use syn::{parenthesized, token, Ident, Result, Token, Type};
+/// use syn::parse::{Parse, ParseStream};
+/// use syn::punctuated::Punctuated;
+///
+/// // Parse a simplified tuple struct syntax like:
+/// //
+/// // struct S(A, B);
+/// struct TupleStruct {
+/// struct_token: Token![struct],
+/// ident: Ident,
+/// paren_token: token::Paren,
+/// fields: Punctuated<Type, Token![,]>,
+/// semi_token: Token![;],
+/// }
+///
+/// impl Parse for TupleStruct {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// let content;
+/// Ok(TupleStruct {
+/// struct_token: input.parse()?,
+/// ident: input.parse()?,
+/// paren_token: parenthesized!(content in input),
+/// fields: content.parse_terminated(Type::parse)?,
+/// semi_token: input.parse()?,
+/// })
+/// }
+/// }
+/// #
+/// # fn main() {
+/// # let input = quote! {
+/// # struct S(A, B);
+/// # };
+/// # syn::parse2::<TupleStruct>(input).unwrap();
+/// # }
+/// ```
+#[macro_export]
+macro_rules! parenthesized {
+ ($content:ident in $cursor:expr) => {
+ match $crate::group::parse_parens(&$cursor) {
+ $crate::export::Ok(parens) => {
+ $content = parens.content;
+ parens.token
+ }
+ $crate::export::Err(error) => {
+ return $crate::export::Err(error);
+ }
+ }
+ };
+}
+
+/// Parse a set of curly braces and expose their content to subsequent parsers.
+///
+/// # Example
+///
+/// ```
+/// # use quote::quote;
+/// #
+/// use syn::{braced, token, Ident, Result, Token, Type};
+/// use syn::parse::{Parse, ParseStream};
+/// use syn::punctuated::Punctuated;
+///
+/// // Parse a simplified struct syntax like:
+/// //
+/// // struct S {
+/// // a: A,
+/// // b: B,
+/// // }
+/// struct Struct {
+/// struct_token: Token![struct],
+/// ident: Ident,
+/// brace_token: token::Brace,
+/// fields: Punctuated<Field, Token![,]>,
+/// }
+///
+/// struct Field {
+/// name: Ident,
+/// colon_token: Token![:],
+/// ty: Type,
+/// }
+///
+/// impl Parse for Struct {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// let content;
+/// Ok(Struct {
+/// struct_token: input.parse()?,
+/// ident: input.parse()?,
+/// brace_token: braced!(content in input),
+/// fields: content.parse_terminated(Field::parse)?,
+/// })
+/// }
+/// }
+///
+/// impl Parse for Field {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// Ok(Field {
+/// name: input.parse()?,
+/// colon_token: input.parse()?,
+/// ty: input.parse()?,
+/// })
+/// }
+/// }
+/// #
+/// # fn main() {
+/// # let input = quote! {
+/// # struct S {
+/// # a: A,
+/// # b: B,
+/// # }
+/// # };
+/// # syn::parse2::<Struct>(input).unwrap();
+/// # }
+/// ```
+#[macro_export]
+macro_rules! braced {
+ ($content:ident in $cursor:expr) => {
+ match $crate::group::parse_braces(&$cursor) {
+ $crate::export::Ok(braces) => {
+ $content = braces.content;
+ braces.token
+ }
+ $crate::export::Err(error) => {
+ return $crate::export::Err(error);
+ }
+ }
+ };
+}
+
+/// Parse a set of square brackets and expose their content to subsequent
+/// parsers.
+///
+/// # Example
+///
+/// ```
+/// # use quote::quote;
+/// #
+/// use proc_macro2::TokenStream;
+/// use syn::{bracketed, token, Result, Token};
+/// use syn::parse::{Parse, ParseStream};
+///
+/// // Parse an outer attribute like:
+/// //
+/// // #[repr(C, packed)]
+/// struct OuterAttribute {
+/// pound_token: Token![#],
+/// bracket_token: token::Bracket,
+/// content: TokenStream,
+/// }
+///
+/// impl Parse for OuterAttribute {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// let content;
+/// Ok(OuterAttribute {
+/// pound_token: input.parse()?,
+/// bracket_token: bracketed!(content in input),
+/// content: content.parse()?,
+/// })
+/// }
+/// }
+/// #
+/// # fn main() {
+/// # let input = quote! {
+/// # #[repr(C, packed)]
+/// # };
+/// # syn::parse2::<OuterAttribute>(input).unwrap();
+/// # }
+/// ```
+#[macro_export]
+macro_rules! bracketed {
+ ($content:ident in $cursor:expr) => {
+ match $crate::group::parse_brackets(&$cursor) {
+ $crate::export::Ok(brackets) => {
+ $content = brackets.content;
+ brackets.token
+ }
+ $crate::export::Err(error) => {
+ return $crate::export::Err(error);
+ }
+ }
+ };
+}
diff --git a/syn/src/ident.rs b/syn/src/ident.rs
new file mode 100644
index 0000000..4ca7484
--- /dev/null
+++ b/syn/src/ident.rs
@@ -0,0 +1,101 @@
+#[cfg(feature = "parsing")]
+use crate::buffer::Cursor;
+#[cfg(feature = "parsing")]
+use crate::lookahead;
+#[cfg(feature = "parsing")]
+use crate::parse::{Parse, ParseStream, Result};
+#[cfg(feature = "parsing")]
+use crate::token::Token;
+use unicode_xid::UnicodeXID;
+
+pub use proc_macro2::Ident;
+
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[allow(non_snake_case)]
+pub fn Ident(marker: lookahead::TokenMarker) -> Ident {
+ match marker {}
+}
+
+#[cfg(feature = "parsing")]
+fn accept_as_ident(ident: &Ident) -> bool {
+ match ident.to_string().as_str() {
+ "_" |
+ // Based on https://doc.rust-lang.org/grammar.html#keywords
+ // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md
+ // and https://github.com/rust-lang/rfcs/blob/master/text/2420-unreserve-proc.md
+ "abstract" | "as" | "become" | "box" | "break" | "const" | "continue" |
+ "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" |
+ "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" |
+ "mod" | "move" | "mut" | "override" | "priv" | "pub" | "ref" |
+ "return" | "Self" | "self" | "static" | "struct" | "super" | "trait" |
+ "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" |
+ "where" | "while" | "yield" => false,
+ _ => true,
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Parse for Ident {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| {
+ if let Some((ident, rest)) = cursor.ident() {
+ if accept_as_ident(&ident) {
+ return Ok((ident, rest));
+ }
+ }
+ Err(cursor.error("expected identifier"))
+ })
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Token for Ident {
+ fn peek(cursor: Cursor) -> bool {
+ if let Some((ident, _rest)) = cursor.ident() {
+ accept_as_ident(&ident)
+ } else {
+ false
+ }
+ }
+
+ fn display() -> &'static str {
+ "identifier"
+ }
+}
+
+macro_rules! ident_from_token {
+ ($token:ident) => {
+ impl From<Token![$token]> for Ident {
+ fn from(token: Token![$token]) -> Ident {
+ Ident::new(stringify!($token), token.span)
+ }
+ }
+ };
+}
+
+ident_from_token!(self);
+ident_from_token!(Self);
+ident_from_token!(super);
+ident_from_token!(crate);
+ident_from_token!(extern);
+
+impl From<Token![_]> for Ident {
+ fn from(token: Token![_]) -> Ident {
+ Ident::new("_", token.span)
+ }
+}
+
+pub fn xid_ok(symbol: &str) -> bool {
+ let mut chars = symbol.chars();
+ let first = chars.next().unwrap();
+ if !(UnicodeXID::is_xid_start(first) || first == '_') {
+ return false;
+ }
+ for ch in chars {
+ if !UnicodeXID::is_xid_continue(ch) {
+ return false;
+ }
+ }
+ true
+}
diff --git a/syn/src/item.rs b/syn/src/item.rs
new file mode 100644
index 0000000..67284a2
--- /dev/null
+++ b/syn/src/item.rs
@@ -0,0 +1,3104 @@
+use super::*;
+use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
+use crate::punctuated::Punctuated;
+use proc_macro2::TokenStream;
+
+#[cfg(feature = "extra-traits")]
+use crate::tt::TokenStreamHelper;
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+#[cfg(feature = "parsing")]
+use std::mem;
+
+ast_enum_of_structs! {
+ /// Things that can appear directly inside of a module or scope.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum Item #manual_extra_traits {
+ /// A constant item: `const MAX: u16 = 65535`.
+ Const(ItemConst),
+
+ /// An enum definition: `enum Foo<A, B> { A(A), B(B) }`.
+ Enum(ItemEnum),
+
+ /// An `extern crate` item: `extern crate serde`.
+ ExternCrate(ItemExternCrate),
+
+ /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
+ /// }`.
+ Fn(ItemFn),
+
+ /// A block of foreign items: `extern "C" { ... }`.
+ ForeignMod(ItemForeignMod),
+
+ /// An impl block providing trait or associated items: `impl<A> Trait
+ /// for Data<A> { ... }`.
+ Impl(ItemImpl),
+
+ /// A macro invocation, which includes `macro_rules!` definitions.
+ Macro(ItemMacro),
+
+ /// A 2.0-style declarative macro introduced by the `macro` keyword.
+ Macro2(ItemMacro2),
+
+ /// A module or module declaration: `mod m` or `mod m { ... }`.
+ Mod(ItemMod),
+
+ /// A static item: `static BIKE: Shed = Shed(42)`.
+ Static(ItemStatic),
+
+ /// A struct definition: `struct Foo<A> { x: A }`.
+ Struct(ItemStruct),
+
+ /// A trait definition: `pub trait Iterator { ... }`.
+ Trait(ItemTrait),
+
+ /// A trait alias: `pub trait SharableIterator = Iterator + Sync`.
+ TraitAlias(ItemTraitAlias),
+
+ /// A type alias: `type Result<T> = std::result::Result<T, MyError>`.
+ Type(ItemType),
+
+ /// A union definition: `union Foo<A, B> { x: A, y: B }`.
+ Union(ItemUnion),
+
+ /// A use declaration: `use std::collections::HashMap`.
+ Use(ItemUse),
+
+ /// Tokens forming an item not interpreted by Syn.
+ Verbatim(TokenStream),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// A constant item: `const MAX: u16 = 65535`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemConst {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub const_token: Token![const],
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ pub eq_token: Token![=],
+ pub expr: Box<Expr>,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// An enum definition: `enum Foo<A, B> { A(A), B(B) }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemEnum {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub enum_token: Token![enum],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub brace_token: token::Brace,
+ pub variants: Punctuated<Variant, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// An `extern crate` item: `extern crate serde`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemExternCrate {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub extern_token: Token![extern],
+ pub crate_token: Token![crate],
+ pub ident: Ident,
+ pub rename: Option<(Token![as], Ident)>,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
+ /// }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemFn {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub sig: Signature,
+ pub block: Box<Block>,
+ }
+}
+
+ast_struct! {
+ /// A block of foreign items: `extern "C" { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemForeignMod {
+ pub attrs: Vec<Attribute>,
+ pub abi: Abi,
+ pub brace_token: token::Brace,
+ pub items: Vec<ForeignItem>,
+ }
+}
+
+ast_struct! {
+ /// An impl block providing trait or associated items: `impl<A> Trait
+ /// for Data<A> { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemImpl {
+ pub attrs: Vec<Attribute>,
+ pub defaultness: Option<Token![default]>,
+ pub unsafety: Option<Token![unsafe]>,
+ pub impl_token: Token![impl],
+ pub generics: Generics,
+ /// Trait this impl implements.
+ pub trait_: Option<(Option<Token![!]>, Path, Token![for])>,
+ /// The Self type of the impl.
+ pub self_ty: Box<Type>,
+ pub brace_token: token::Brace,
+ pub items: Vec<ImplItem>,
+ }
+}
+
+ast_struct! {
+ /// A macro invocation, which includes `macro_rules!` definitions.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemMacro {
+ pub attrs: Vec<Attribute>,
+ /// The `example` in `macro_rules! example { ... }`.
+ pub ident: Option<Ident>,
+ pub mac: Macro,
+ pub semi_token: Option<Token![;]>,
+ }
+}
+
+ast_struct! {
+ /// A 2.0-style declarative macro introduced by the `macro` keyword.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemMacro2 #manual_extra_traits {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub macro_token: Token![macro],
+ pub ident: Ident,
+ pub rules: TokenStream,
+ }
+}
+
+ast_struct! {
+ /// A module or module declaration: `mod m` or `mod m { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemMod {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub mod_token: Token![mod],
+ pub ident: Ident,
+ pub content: Option<(token::Brace, Vec<Item>)>,
+ pub semi: Option<Token![;]>,
+ }
+}
+
+ast_struct! {
+ /// A static item: `static BIKE: Shed = Shed(42)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemStatic {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub static_token: Token![static],
+ pub mutability: Option<Token![mut]>,
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ pub eq_token: Token![=],
+ pub expr: Box<Expr>,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A struct definition: `struct Foo<A> { x: A }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemStruct {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub struct_token: Token![struct],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub fields: Fields,
+ pub semi_token: Option<Token![;]>,
+ }
+}
+
+ast_struct! {
+ /// A trait definition: `pub trait Iterator { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemTrait {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub unsafety: Option<Token![unsafe]>,
+ pub auto_token: Option<Token![auto]>,
+ pub trait_token: Token![trait],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub colon_token: Option<Token![:]>,
+ pub supertraits: Punctuated<TypeParamBound, Token![+]>,
+ pub brace_token: token::Brace,
+ pub items: Vec<TraitItem>,
+ }
+}
+
+ast_struct! {
+ /// A trait alias: `pub trait SharableIterator = Iterator + Sync`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemTraitAlias {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub trait_token: Token![trait],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub eq_token: Token![=],
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A type alias: `type Result<T> = std::result::Result<T, MyError>`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemType {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub eq_token: Token![=],
+ pub ty: Box<Type>,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A union definition: `union Foo<A, B> { x: A, y: B }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemUnion {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub union_token: Token![union],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub fields: FieldsNamed,
+ }
+}
+
+ast_struct! {
+ /// A use declaration: `use std::collections::HashMap`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ItemUse {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub use_token: Token![use],
+ pub leading_colon: Option<Token![::]>,
+ pub tree: UseTree,
+ pub semi_token: Token![;],
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Item {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Item {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Item::Const(this), Item::Const(other)) => this == other,
+ (Item::Enum(this), Item::Enum(other)) => this == other,
+ (Item::ExternCrate(this), Item::ExternCrate(other)) => this == other,
+ (Item::Fn(this), Item::Fn(other)) => this == other,
+ (Item::ForeignMod(this), Item::ForeignMod(other)) => this == other,
+ (Item::Impl(this), Item::Impl(other)) => this == other,
+ (Item::Macro(this), Item::Macro(other)) => this == other,
+ (Item::Macro2(this), Item::Macro2(other)) => this == other,
+ (Item::Mod(this), Item::Mod(other)) => this == other,
+ (Item::Static(this), Item::Static(other)) => this == other,
+ (Item::Struct(this), Item::Struct(other)) => this == other,
+ (Item::Trait(this), Item::Trait(other)) => this == other,
+ (Item::TraitAlias(this), Item::TraitAlias(other)) => this == other,
+ (Item::Type(this), Item::Type(other)) => this == other,
+ (Item::Union(this), Item::Union(other)) => this == other,
+ (Item::Use(this), Item::Use(other)) => this == other,
+ (Item::Verbatim(this), Item::Verbatim(other)) => {
+ TokenStreamHelper(this) == TokenStreamHelper(other)
+ }
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Item {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ Item::Const(item) => {
+ state.write_u8(0);
+ item.hash(state);
+ }
+ Item::Enum(item) => {
+ state.write_u8(1);
+ item.hash(state);
+ }
+ Item::ExternCrate(item) => {
+ state.write_u8(2);
+ item.hash(state);
+ }
+ Item::Fn(item) => {
+ state.write_u8(3);
+ item.hash(state);
+ }
+ Item::ForeignMod(item) => {
+ state.write_u8(4);
+ item.hash(state);
+ }
+ Item::Impl(item) => {
+ state.write_u8(5);
+ item.hash(state);
+ }
+ Item::Macro(item) => {
+ state.write_u8(6);
+ item.hash(state);
+ }
+ Item::Macro2(item) => {
+ state.write_u8(7);
+ item.hash(state);
+ }
+ Item::Mod(item) => {
+ state.write_u8(8);
+ item.hash(state);
+ }
+ Item::Static(item) => {
+ state.write_u8(9);
+ item.hash(state);
+ }
+ Item::Struct(item) => {
+ state.write_u8(10);
+ item.hash(state);
+ }
+ Item::Trait(item) => {
+ state.write_u8(11);
+ item.hash(state);
+ }
+ Item::TraitAlias(item) => {
+ state.write_u8(12);
+ item.hash(state);
+ }
+ Item::Type(item) => {
+ state.write_u8(13);
+ item.hash(state);
+ }
+ Item::Union(item) => {
+ state.write_u8(14);
+ item.hash(state);
+ }
+ Item::Use(item) => {
+ state.write_u8(15);
+ item.hash(state);
+ }
+ Item::Verbatim(item) => {
+ state.write_u8(16);
+ TokenStreamHelper(item).hash(state);
+ }
+ Item::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+impl Item {
+ #[cfg(feature = "parsing")]
+ pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> {
+ match self {
+ Item::ExternCrate(ItemExternCrate { attrs, .. })
+ | Item::Use(ItemUse { attrs, .. })
+ | Item::Static(ItemStatic { attrs, .. })
+ | Item::Const(ItemConst { attrs, .. })
+ | Item::Fn(ItemFn { attrs, .. })
+ | Item::Mod(ItemMod { attrs, .. })
+ | Item::ForeignMod(ItemForeignMod { attrs, .. })
+ | Item::Type(ItemType { attrs, .. })
+ | Item::Struct(ItemStruct { attrs, .. })
+ | Item::Enum(ItemEnum { attrs, .. })
+ | Item::Union(ItemUnion { attrs, .. })
+ | Item::Trait(ItemTrait { attrs, .. })
+ | Item::TraitAlias(ItemTraitAlias { attrs, .. })
+ | Item::Impl(ItemImpl { attrs, .. })
+ | Item::Macro(ItemMacro { attrs, .. })
+ | Item::Macro2(ItemMacro2 { attrs, .. }) => mem::replace(attrs, new),
+ Item::Verbatim(_) => Vec::new(),
+ Item::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for ItemMacro2 {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ItemMacro2 {
+ fn eq(&self, other: &Self) -> bool {
+ self.attrs == other.attrs
+ && self.vis == other.vis
+ && self.macro_token == other.macro_token
+ && self.ident == other.ident
+ && TokenStreamHelper(&self.rules) == TokenStreamHelper(&other.rules)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ItemMacro2 {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.attrs.hash(state);
+ self.vis.hash(state);
+ self.macro_token.hash(state);
+ self.ident.hash(state);
+ TokenStreamHelper(&self.rules).hash(state);
+ }
+}
+
+impl From<DeriveInput> for Item {
+ fn from(input: DeriveInput) -> Item {
+ match input.data {
+ Data::Struct(data) => Item::Struct(ItemStruct {
+ attrs: input.attrs,
+ vis: input.vis,
+ struct_token: data.struct_token,
+ ident: input.ident,
+ generics: input.generics,
+ fields: data.fields,
+ semi_token: data.semi_token,
+ }),
+ Data::Enum(data) => Item::Enum(ItemEnum {
+ attrs: input.attrs,
+ vis: input.vis,
+ enum_token: data.enum_token,
+ ident: input.ident,
+ generics: input.generics,
+ brace_token: data.brace_token,
+ variants: data.variants,
+ }),
+ Data::Union(data) => Item::Union(ItemUnion {
+ attrs: input.attrs,
+ vis: input.vis,
+ union_token: data.union_token,
+ ident: input.ident,
+ generics: input.generics,
+ fields: data.fields,
+ }),
+ }
+ }
+}
+
+impl From<ItemStruct> for DeriveInput {
+ fn from(input: ItemStruct) -> DeriveInput {
+ DeriveInput {
+ attrs: input.attrs,
+ vis: input.vis,
+ ident: input.ident,
+ generics: input.generics,
+ data: Data::Struct(DataStruct {
+ struct_token: input.struct_token,
+ fields: input.fields,
+ semi_token: input.semi_token,
+ }),
+ }
+ }
+}
+
+impl From<ItemEnum> for DeriveInput {
+ fn from(input: ItemEnum) -> DeriveInput {
+ DeriveInput {
+ attrs: input.attrs,
+ vis: input.vis,
+ ident: input.ident,
+ generics: input.generics,
+ data: Data::Enum(DataEnum {
+ enum_token: input.enum_token,
+ brace_token: input.brace_token,
+ variants: input.variants,
+ }),
+ }
+ }
+}
+
+impl From<ItemUnion> for DeriveInput {
+ fn from(input: ItemUnion) -> DeriveInput {
+ DeriveInput {
+ attrs: input.attrs,
+ vis: input.vis,
+ ident: input.ident,
+ generics: input.generics,
+ data: Data::Union(DataUnion {
+ union_token: input.union_token,
+ fields: input.fields,
+ }),
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// A suffix of an import tree in a `use` item: `Type as Renamed` or `*`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum UseTree {
+ /// A path prefix of imports in a `use` item: `std::...`.
+ Path(UsePath),
+
+ /// An identifier imported by a `use` item: `HashMap`.
+ Name(UseName),
+
+ /// An renamed identifier imported by a `use` item: `HashMap as Map`.
+ Rename(UseRename),
+
+ /// A glob import in a `use` item: `*`.
+ Glob(UseGlob),
+
+ /// A braced group of imports in a `use` item: `{A, B, C}`.
+ Group(UseGroup),
+ }
+}
+
+ast_struct! {
+ /// A path prefix of imports in a `use` item: `std::...`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct UsePath {
+ pub ident: Ident,
+ pub colon2_token: Token![::],
+ pub tree: Box<UseTree>,
+ }
+}
+
+ast_struct! {
+ /// An identifier imported by a `use` item: `HashMap`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct UseName {
+ pub ident: Ident,
+ }
+}
+
+ast_struct! {
+ /// An renamed identifier imported by a `use` item: `HashMap as Map`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct UseRename {
+ pub ident: Ident,
+ pub as_token: Token![as],
+ pub rename: Ident,
+ }
+}
+
+ast_struct! {
+ /// A glob import in a `use` item: `*`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct UseGlob {
+ pub star_token: Token![*],
+ }
+}
+
+ast_struct! {
+ /// A braced group of imports in a `use` item: `{A, B, C}`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct UseGroup {
+ pub brace_token: token::Brace,
+ pub items: Punctuated<UseTree, Token![,]>,
+ }
+}
+
+ast_enum_of_structs! {
+ /// An item within an `extern` block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum ForeignItem #manual_extra_traits {
+ /// A foreign function in an `extern` block.
+ Fn(ForeignItemFn),
+
+ /// A foreign static item in an `extern` block: `static ext: u8`.
+ Static(ForeignItemStatic),
+
+ /// A foreign type in an `extern` block: `type void`.
+ Type(ForeignItemType),
+
+ /// A macro invocation within an extern block.
+ Macro(ForeignItemMacro),
+
+ /// Tokens in an `extern` block not interpreted by Syn.
+ Verbatim(TokenStream),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// A foreign function in an `extern` block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ForeignItemFn {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub sig: Signature,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A foreign static item in an `extern` block: `static ext: u8`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ForeignItemStatic {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub static_token: Token![static],
+ pub mutability: Option<Token![mut]>,
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A foreign type in an `extern` block: `type void`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ForeignItemType {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A macro invocation within an extern block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ForeignItemMacro {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ pub semi_token: Option<Token![;]>,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for ForeignItem {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ForeignItem {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (ForeignItem::Fn(this), ForeignItem::Fn(other)) => this == other,
+ (ForeignItem::Static(this), ForeignItem::Static(other)) => this == other,
+ (ForeignItem::Type(this), ForeignItem::Type(other)) => this == other,
+ (ForeignItem::Macro(this), ForeignItem::Macro(other)) => this == other,
+ (ForeignItem::Verbatim(this), ForeignItem::Verbatim(other)) => {
+ TokenStreamHelper(this) == TokenStreamHelper(other)
+ }
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ForeignItem {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ ForeignItem::Fn(item) => {
+ state.write_u8(0);
+ item.hash(state);
+ }
+ ForeignItem::Static(item) => {
+ state.write_u8(1);
+ item.hash(state);
+ }
+ ForeignItem::Type(item) => {
+ state.write_u8(2);
+ item.hash(state);
+ }
+ ForeignItem::Macro(item) => {
+ state.write_u8(3);
+ item.hash(state);
+ }
+ ForeignItem::Verbatim(item) => {
+ state.write_u8(4);
+ TokenStreamHelper(item).hash(state);
+ }
+ ForeignItem::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// An item declaration within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum TraitItem #manual_extra_traits {
+ /// An associated constant within the definition of a trait.
+ Const(TraitItemConst),
+
+ /// A trait method within the definition of a trait.
+ Method(TraitItemMethod),
+
+ /// An associated type within the definition of a trait.
+ Type(TraitItemType),
+
+ /// A macro invocation within the definition of a trait.
+ Macro(TraitItemMacro),
+
+ /// Tokens within the definition of a trait not interpreted by Syn.
+ Verbatim(TokenStream),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// An associated constant within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct TraitItemConst {
+ pub attrs: Vec<Attribute>,
+ pub const_token: Token![const],
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Type,
+ pub default: Option<(Token![=], Expr)>,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A trait method within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct TraitItemMethod {
+ pub attrs: Vec<Attribute>,
+ pub sig: Signature,
+ pub default: Option<Block>,
+ pub semi_token: Option<Token![;]>,
+ }
+}
+
+ast_struct! {
+ /// An associated type within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct TraitItemType {
+ pub attrs: Vec<Attribute>,
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ pub default: Option<(Token![=], Type)>,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A macro invocation within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct TraitItemMacro {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ pub semi_token: Option<Token![;]>,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for TraitItem {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for TraitItem {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (TraitItem::Const(this), TraitItem::Const(other)) => this == other,
+ (TraitItem::Method(this), TraitItem::Method(other)) => this == other,
+ (TraitItem::Type(this), TraitItem::Type(other)) => this == other,
+ (TraitItem::Macro(this), TraitItem::Macro(other)) => this == other,
+ (TraitItem::Verbatim(this), TraitItem::Verbatim(other)) => {
+ TokenStreamHelper(this) == TokenStreamHelper(other)
+ }
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for TraitItem {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ TraitItem::Const(item) => {
+ state.write_u8(0);
+ item.hash(state);
+ }
+ TraitItem::Method(item) => {
+ state.write_u8(1);
+ item.hash(state);
+ }
+ TraitItem::Type(item) => {
+ state.write_u8(2);
+ item.hash(state);
+ }
+ TraitItem::Macro(item) => {
+ state.write_u8(3);
+ item.hash(state);
+ }
+ TraitItem::Verbatim(item) => {
+ state.write_u8(4);
+ TokenStreamHelper(item).hash(state);
+ }
+ TraitItem::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// An item within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum ImplItem #manual_extra_traits {
+ /// An associated constant within an impl block.
+ Const(ImplItemConst),
+
+ /// A method within an impl block.
+ Method(ImplItemMethod),
+
+ /// An associated type within an impl block.
+ Type(ImplItemType),
+
+ /// A macro invocation within an impl block.
+ Macro(ImplItemMacro),
+
+ /// Tokens within an impl block not interpreted by Syn.
+ Verbatim(TokenStream),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// An associated constant within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ImplItemConst {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: Option<Token![default]>,
+ pub const_token: Token![const],
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Type,
+ pub eq_token: Token![=],
+ pub expr: Expr,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A method within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ImplItemMethod {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: Option<Token![default]>,
+ pub sig: Signature,
+ pub block: Block,
+ }
+}
+
+ast_struct! {
+ /// An associated type within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ImplItemType {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: Option<Token![default]>,
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub eq_token: Token![=],
+ pub ty: Type,
+ pub semi_token: Token![;],
+ }
+}
+
+ast_struct! {
+ /// A macro invocation within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct ImplItemMacro {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ pub semi_token: Option<Token![;]>,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for ImplItem {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ImplItem {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (ImplItem::Const(this), ImplItem::Const(other)) => this == other,
+ (ImplItem::Method(this), ImplItem::Method(other)) => this == other,
+ (ImplItem::Type(this), ImplItem::Type(other)) => this == other,
+ (ImplItem::Macro(this), ImplItem::Macro(other)) => this == other,
+ (ImplItem::Verbatim(this), ImplItem::Verbatim(other)) => {
+ TokenStreamHelper(this) == TokenStreamHelper(other)
+ }
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ImplItem {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ ImplItem::Const(item) => {
+ state.write_u8(0);
+ item.hash(state);
+ }
+ ImplItem::Method(item) => {
+ state.write_u8(1);
+ item.hash(state);
+ }
+ ImplItem::Type(item) => {
+ state.write_u8(2);
+ item.hash(state);
+ }
+ ImplItem::Macro(item) => {
+ state.write_u8(3);
+ item.hash(state);
+ }
+ ImplItem::Verbatim(item) => {
+ state.write_u8(4);
+ TokenStreamHelper(item).hash(state);
+ }
+ ImplItem::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+ast_struct! {
+ /// A function signature in a trait or implementation: `unsafe fn
+ /// initialize(&self)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Signature {
+ pub constness: Option<Token![const]>,
+ pub asyncness: Option<Token![async]>,
+ pub unsafety: Option<Token![unsafe]>,
+ pub abi: Option<Abi>,
+ pub fn_token: Token![fn],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub paren_token: token::Paren,
+ pub inputs: Punctuated<FnArg, Token![,]>,
+ pub variadic: Option<Variadic>,
+ pub output: ReturnType,
+ }
+}
+
+impl Signature {
+ /// A method's `self` receiver, such as `&self` or `self: Box<Self>`.
+ pub fn receiver(&self) -> Option<&FnArg> {
+ let arg = self.inputs.first()?;
+ match arg {
+ FnArg::Receiver(_) => Some(arg),
+ FnArg::Typed(PatType { pat, .. }) => {
+ if let Pat::Ident(PatIdent { ident, .. }) = &**pat {
+ if ident == "self" {
+ return Some(arg);
+ }
+ }
+ None
+ }
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub enum FnArg {
+ /// The `self` argument of an associated method, whether taken by value
+ /// or by reference.
+ ///
+ /// Note that `self` receivers with a specified type, such as `self:
+ /// Box<Self>`, are parsed as a `FnArg::Typed`.
+ Receiver(Receiver),
+
+ /// A function argument accepted by pattern and type.
+ Typed(PatType),
+ }
+}
+
+ast_struct! {
+ /// The `self` argument of an associated method, whether taken by value
+ /// or by reference.
+ ///
+ /// Note that `self` receivers with a specified type, such as `self:
+ /// Box<Self>`, are parsed as a `FnArg::Typed`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Receiver {
+ pub attrs: Vec<Attribute>,
+ pub reference: Option<(Token![&], Option<Lifetime>)>,
+ pub mutability: Option<Token![mut]>,
+ pub self_token: Token![self],
+ }
+}
+
+impl Receiver {
+ pub fn lifetime(&self) -> Option<&Lifetime> {
+ self.reference.as_ref()?.1.as_ref()
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::ext::IdentExt;
+ use crate::parse::discouraged::Speculative;
+ use crate::parse::{Parse, ParseStream, Result};
+ use crate::token::Brace;
+ use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenTree};
+ use std::iter::{self, FromIterator};
+
+ crate::custom_keyword!(existential);
+
+ impl Parse for Item {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut attrs = input.call(Attribute::parse_outer)?;
+ let ahead = input.fork();
+ let vis: Visibility = ahead.parse()?;
+
+ let lookahead = ahead.lookahead1();
+ let mut item = if lookahead.peek(Token![extern]) {
+ ahead.parse::<Token![extern]>()?;
+ let lookahead = ahead.lookahead1();
+ if lookahead.peek(Token![crate]) {
+ input.parse().map(Item::ExternCrate)
+ } else if lookahead.peek(Token![fn]) {
+ input.parse().map(Item::Fn)
+ } else if lookahead.peek(token::Brace) {
+ input.parse().map(Item::ForeignMod)
+ } else if lookahead.peek(LitStr) {
+ ahead.parse::<LitStr>()?;
+ let lookahead = ahead.lookahead1();
+ if lookahead.peek(token::Brace) {
+ input.parse().map(Item::ForeignMod)
+ } else if lookahead.peek(Token![fn]) {
+ input.parse().map(Item::Fn)
+ } else {
+ Err(lookahead.error())
+ }
+ } else {
+ Err(lookahead.error())
+ }
+ } else if lookahead.peek(Token![use]) {
+ input.parse().map(Item::Use)
+ } else if lookahead.peek(Token![static]) {
+ input.parse().map(Item::Static)
+ } else if lookahead.peek(Token![const]) {
+ ahead.parse::<Token![const]>()?;
+ let lookahead = ahead.lookahead1();
+ if lookahead.peek(Ident) || lookahead.peek(Token![_]) {
+ input.parse().map(Item::Const)
+ } else if lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![async])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ input.parse().map(Item::Fn)
+ } else {
+ Err(lookahead.error())
+ }
+ } else if lookahead.peek(Token![unsafe]) {
+ ahead.parse::<Token![unsafe]>()?;
+ let lookahead = ahead.lookahead1();
+ if lookahead.peek(Token![trait])
+ || lookahead.peek(Token![auto]) && ahead.peek2(Token![trait])
+ {
+ input.parse().map(Item::Trait)
+ } else if lookahead.peek(Token![impl]) {
+ input.parse().map(Item::Impl)
+ } else if lookahead.peek(Token![async])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ input.parse().map(Item::Fn)
+ } else {
+ Err(lookahead.error())
+ }
+ } else if lookahead.peek(Token![async]) || lookahead.peek(Token![fn]) {
+ input.parse().map(Item::Fn)
+ } else if lookahead.peek(Token![mod]) {
+ input.parse().map(Item::Mod)
+ } else if lookahead.peek(Token![type]) {
+ input.parse().map(Item::Type)
+ } else if lookahead.peek(existential) {
+ input.call(item_existential).map(Item::Verbatim)
+ } else if lookahead.peek(Token![struct]) {
+ input.parse().map(Item::Struct)
+ } else if lookahead.peek(Token![enum]) {
+ input.parse().map(Item::Enum)
+ } else if lookahead.peek(Token![union]) && ahead.peek2(Ident) {
+ input.parse().map(Item::Union)
+ } else if lookahead.peek(Token![trait]) {
+ input.call(parse_trait_or_trait_alias)
+ } else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) {
+ input.parse().map(Item::Trait)
+ } else if lookahead.peek(Token![impl])
+ || lookahead.peek(Token![default]) && !ahead.peek2(Token![!])
+ {
+ input.parse().map(Item::Impl)
+ } else if lookahead.peek(Token![macro]) {
+ input.parse().map(Item::Macro2)
+ } else if vis.is_inherited()
+ && (lookahead.peek(Ident)
+ || lookahead.peek(Token![self])
+ || lookahead.peek(Token![super])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![crate])
+ || lookahead.peek(Token![::]))
+ {
+ input.parse().map(Item::Macro)
+ } else {
+ Err(lookahead.error())
+ }?;
+
+ attrs.extend(item.replace_attrs(Vec::new()));
+ item.replace_attrs(attrs);
+ Ok(item)
+ }
+ }
+
+ impl Parse for ItemMacro {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let path = input.call(Path::parse_mod_style)?;
+ let bang_token: Token![!] = input.parse()?;
+ let ident: Option<Ident> = input.parse()?;
+ let (delimiter, tokens) = input.call(mac::parse_delimiter)?;
+ let semi_token: Option<Token![;]> = if !delimiter.is_brace() {
+ Some(input.parse()?)
+ } else {
+ None
+ };
+ Ok(ItemMacro {
+ attrs,
+ ident,
+ mac: Macro {
+ path,
+ bang_token,
+ delimiter,
+ tokens,
+ },
+ semi_token,
+ })
+ }
+ }
+
+ impl Parse for ItemMacro2 {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let macro_token: Token![macro] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let mut rules = TokenStream::new();
+
+ let mut lookahead = input.lookahead1();
+ if lookahead.peek(token::Paren) {
+ let paren_content;
+ let paren_token = parenthesized!(paren_content in input);
+ let args: TokenStream = paren_content.parse()?;
+ let mut args = Group::new(Delimiter::Parenthesis, args);
+ args.set_span(paren_token.span);
+ rules.extend(iter::once(TokenTree::Group(args)));
+ lookahead = input.lookahead1();
+ }
+
+ if lookahead.peek(token::Brace) {
+ let brace_content;
+ let brace_token = braced!(brace_content in input);
+ let body: TokenStream = brace_content.parse()?;
+ let mut body = Group::new(Delimiter::Brace, body);
+ body.set_span(brace_token.span);
+ rules.extend(iter::once(TokenTree::Group(body)));
+ } else {
+ return Err(lookahead.error());
+ }
+
+ Ok(ItemMacro2 {
+ attrs,
+ vis,
+ macro_token,
+ ident,
+ rules,
+ })
+ }
+ }
+
+ impl Parse for ItemExternCrate {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ItemExternCrate {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ extern_token: input.parse()?,
+ crate_token: input.parse()?,
+ ident: {
+ if input.peek(Token![self]) {
+ input.call(Ident::parse_any)?
+ } else {
+ input.parse()?
+ }
+ },
+ rename: {
+ if input.peek(Token![as]) {
+ let as_token: Token![as] = input.parse()?;
+ let rename: Ident = if input.peek(Token![_]) {
+ Ident::from(input.parse::<Token![_]>()?)
+ } else {
+ input.parse()?
+ };
+ Some((as_token, rename))
+ } else {
+ None
+ }
+ },
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ItemUse {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ItemUse {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ use_token: input.parse()?,
+ leading_colon: input.parse()?,
+ tree: input.parse()?,
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for UseTree {
+ fn parse(input: ParseStream) -> Result<UseTree> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Ident)
+ || lookahead.peek(Token![self])
+ || lookahead.peek(Token![super])
+ || lookahead.peek(Token![crate])
+ || lookahead.peek(Token![extern])
+ {
+ let ident = input.call(Ident::parse_any)?;
+ if input.peek(Token![::]) {
+ Ok(UseTree::Path(UsePath {
+ ident,
+ colon2_token: input.parse()?,
+ tree: Box::new(input.parse()?),
+ }))
+ } else if input.peek(Token![as]) {
+ Ok(UseTree::Rename(UseRename {
+ ident,
+ as_token: input.parse()?,
+ rename: {
+ if input.peek(Ident) {
+ input.parse()?
+ } else if input.peek(Token![_]) {
+ Ident::from(input.parse::<Token![_]>()?)
+ } else {
+ return Err(input.error("expected identifier or underscore"));
+ }
+ },
+ }))
+ } else {
+ Ok(UseTree::Name(UseName { ident }))
+ }
+ } else if lookahead.peek(Token![*]) {
+ Ok(UseTree::Glob(UseGlob {
+ star_token: input.parse()?,
+ }))
+ } else if lookahead.peek(token::Brace) {
+ let content;
+ Ok(UseTree::Group(UseGroup {
+ brace_token: braced!(content in input),
+ items: content.parse_terminated(UseTree::parse)?,
+ }))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ impl Parse for ItemStatic {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ItemStatic {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ static_token: input.parse()?,
+ mutability: input.parse()?,
+ ident: input.parse()?,
+ colon_token: input.parse()?,
+ ty: input.parse()?,
+ eq_token: input.parse()?,
+ expr: input.parse()?,
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ItemConst {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ItemConst {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ const_token: input.parse()?,
+ ident: {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Ident) || lookahead.peek(Token![_]) {
+ input.call(Ident::parse_any)?
+ } else {
+ return Err(lookahead.error());
+ }
+ },
+ colon_token: input.parse()?,
+ ty: input.parse()?,
+ eq_token: input.parse()?,
+ expr: input.parse()?,
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ItemFn {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let constness: Option<Token![const]> = input.parse()?;
+ let asyncness: Option<Token![async]> = input.parse()?;
+ let unsafety: Option<Token![unsafe]> = input.parse()?;
+ let abi: Option<Abi> = input.parse()?;
+ let fn_token: Token![fn] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let generics: Generics = input.parse()?;
+
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let inputs = parse_fn_args(&content)?;
+ let variadic = inputs.last().as_ref().and_then(get_variadic);
+
+ fn get_variadic(input: &&FnArg) -> Option<Variadic> {
+ if let FnArg::Typed(PatType { ty, .. }) = input {
+ if let Type::Verbatim(tokens) = &**ty {
+ if let Ok(dots) = parse2(tokens.clone()) {
+ return Some(Variadic {
+ attrs: Vec::new(),
+ dots,
+ });
+ }
+ }
+ }
+ None
+ }
+
+ let output: ReturnType = input.parse()?;
+ let where_clause: Option<WhereClause> = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+
+ Ok(ItemFn {
+ attrs: private::attrs(outer_attrs, inner_attrs),
+ vis,
+ sig: Signature {
+ constness,
+ asyncness,
+ unsafety,
+ abi,
+ fn_token,
+ ident,
+ paren_token,
+ inputs,
+ output,
+ variadic,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ },
+ block: Box::new(Block { brace_token, stmts }),
+ })
+ }
+ }
+
+ impl Parse for FnArg {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+
+ let ahead = input.fork();
+ if let Ok(mut receiver) = ahead.parse::<Receiver>() {
+ if !ahead.peek(Token![:]) {
+ input.advance_to(&ahead);
+ receiver.attrs = attrs;
+ return Ok(FnArg::Receiver(receiver));
+ }
+ }
+
+ let mut typed = input.call(fn_arg_typed)?;
+ typed.attrs = attrs;
+ Ok(FnArg::Typed(typed))
+ }
+ }
+
+ impl Parse for Receiver {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Receiver {
+ attrs: Vec::new(),
+ reference: {
+ if input.peek(Token![&]) {
+ Some((input.parse()?, input.parse()?))
+ } else {
+ None
+ }
+ },
+ mutability: input.parse()?,
+ self_token: input.parse()?,
+ })
+ }
+ }
+
+ fn parse_fn_args(input: ParseStream) -> Result<Punctuated<FnArg, Token![,]>> {
+ let mut args = Punctuated::new();
+ let mut has_receiver = false;
+ loop {
+ if input.is_empty() {
+ break;
+ }
+ let arg: FnArg = input.parse()?;
+ if let FnArg::Receiver(receiver) = &arg {
+ if has_receiver {
+ return Err(Error::new(
+ receiver.self_token.span,
+ "unexpected second method receiver",
+ ));
+ } else if !args.is_empty() {
+ return Err(Error::new(
+ receiver.self_token.span,
+ "unexpected method receiver",
+ ));
+ }
+ has_receiver = true;
+ }
+ args.push_value(arg);
+ if input.is_empty() {
+ break;
+ }
+ let comma: Token![,] = input.parse()?;
+ args.push_punct(comma);
+ }
+ Ok(args)
+ }
+
+ fn fn_arg_typed(input: ParseStream) -> Result<PatType> {
+ // Hack to parse pre-2018 syntax in
+ // test/ui/rfc-2565-param-attrs/param-attrs-pretty.rs
+ // because the rest of the test case is valuable.
+ if input.peek(Ident) && input.peek2(Token![<]) {
+ let span = input.fork().parse::<Ident>()?.span();
+ return Ok(PatType {
+ attrs: Vec::new(),
+ pat: Box::new(Pat::Wild(PatWild {
+ attrs: Vec::new(),
+ underscore_token: Token![_](span),
+ })),
+ colon_token: Token![:](span),
+ ty: input.parse()?,
+ });
+ }
+
+ Ok(PatType {
+ attrs: Vec::new(),
+ pat: input.parse()?,
+ colon_token: input.parse()?,
+ ty: Box::new(match input.parse::<Option<Token![...]>>()? {
+ Some(dot3) => {
+ let args = vec![
+ TokenTree::Punct(Punct::new('.', Spacing::Joint)),
+ TokenTree::Punct(Punct::new('.', Spacing::Joint)),
+ TokenTree::Punct(Punct::new('.', Spacing::Alone)),
+ ];
+ let tokens = TokenStream::from_iter(args.into_iter().zip(&dot3.spans).map(
+ |(mut arg, span)| {
+ arg.set_span(*span);
+ arg
+ },
+ ));
+ Type::Verbatim(tokens)
+ }
+ None => input.parse()?,
+ }),
+ })
+ }
+
+ impl Parse for ItemMod {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let mod_token: Token![mod] = input.parse()?;
+ let ident: Ident = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![;]) {
+ Ok(ItemMod {
+ attrs: outer_attrs,
+ vis,
+ mod_token,
+ ident,
+ content: None,
+ semi: Some(input.parse()?),
+ })
+ } else if lookahead.peek(token::Brace) {
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+
+ let mut items = Vec::new();
+ while !content.is_empty() {
+ items.push(content.parse()?);
+ }
+
+ Ok(ItemMod {
+ attrs: private::attrs(outer_attrs, inner_attrs),
+ vis,
+ mod_token,
+ ident,
+ content: Some((brace_token, items)),
+ semi: None,
+ })
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ impl Parse for ItemForeignMod {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+ let abi: Abi = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let mut items = Vec::new();
+ while !content.is_empty() {
+ items.push(content.parse()?);
+ }
+
+ Ok(ItemForeignMod {
+ attrs: private::attrs(outer_attrs, inner_attrs),
+ abi,
+ brace_token,
+ items,
+ })
+ }
+ }
+
+ impl Parse for ForeignItem {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut attrs = input.call(Attribute::parse_outer)?;
+ let ahead = input.fork();
+ let vis: Visibility = ahead.parse()?;
+
+ let lookahead = ahead.lookahead1();
+ let mut item = if lookahead.peek(Token![fn]) {
+ input.parse().map(ForeignItem::Fn)
+ } else if lookahead.peek(Token![static]) {
+ input.parse().map(ForeignItem::Static)
+ } else if lookahead.peek(Token![type]) {
+ input.parse().map(ForeignItem::Type)
+ } else if vis.is_inherited()
+ && (lookahead.peek(Ident)
+ || lookahead.peek(Token![self])
+ || lookahead.peek(Token![super])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![crate])
+ || lookahead.peek(Token![::]))
+ {
+ input.parse().map(ForeignItem::Macro)
+ } else {
+ Err(lookahead.error())
+ }?;
+
+ {
+ let item_attrs = match &mut item {
+ ForeignItem::Fn(item) => &mut item.attrs,
+ ForeignItem::Static(item) => &mut item.attrs,
+ ForeignItem::Type(item) => &mut item.attrs,
+ ForeignItem::Macro(item) => &mut item.attrs,
+ ForeignItem::Verbatim(_) | ForeignItem::__Nonexhaustive => unreachable!(),
+ };
+ attrs.extend(item_attrs.drain(..));
+ *item_attrs = attrs;
+ }
+
+ Ok(item)
+ }
+ }
+
+ impl Parse for ForeignItemFn {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let fn_token: Token![fn] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let generics: Generics = input.parse()?;
+
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let mut inputs = Punctuated::new();
+ let mut variadic = None;
+ while !content.is_empty() {
+ let attrs = content.call(Attribute::parse_outer)?;
+
+ if let Some(dots) = content.parse()? {
+ variadic = Some(Variadic { attrs, dots });
+ break;
+ }
+
+ let mut arg = content.call(fn_arg_typed)?;
+ arg.attrs = attrs;
+ inputs.push_value(FnArg::Typed(arg));
+ if content.is_empty() {
+ break;
+ }
+
+ inputs.push_punct(content.parse()?);
+ }
+
+ let output: ReturnType = input.parse()?;
+ let where_clause: Option<WhereClause> = input.parse()?;
+ let semi_token: Token![;] = input.parse()?;
+
+ Ok(ForeignItemFn {
+ attrs,
+ vis,
+ sig: Signature {
+ constness: None,
+ asyncness: None,
+ unsafety: None,
+ abi: None,
+ fn_token,
+ ident,
+ paren_token,
+ inputs,
+ output,
+ variadic,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ },
+ semi_token,
+ })
+ }
+ }
+
+ impl Parse for ForeignItemStatic {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ForeignItemStatic {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ static_token: input.parse()?,
+ mutability: input.parse()?,
+ ident: input.parse()?,
+ colon_token: input.parse()?,
+ ty: input.parse()?,
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ForeignItemType {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ForeignItemType {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ type_token: input.parse()?,
+ ident: input.parse()?,
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ForeignItemMacro {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let mac: Macro = input.parse()?;
+ let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() {
+ None
+ } else {
+ Some(input.parse()?)
+ };
+ Ok(ForeignItemMacro {
+ attrs,
+ mac,
+ semi_token,
+ })
+ }
+ }
+
+ impl Parse for ItemType {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ItemType {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ type_token: input.parse()?,
+ ident: input.parse()?,
+ generics: {
+ let mut generics: Generics = input.parse()?;
+ generics.where_clause = input.parse()?;
+ generics
+ },
+ eq_token: input.parse()?,
+ ty: input.parse()?,
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ #[cfg(not(feature = "printing"))]
+ fn item_existential(input: ParseStream) -> Result<TokenStream> {
+ Err(input.error("existential type is not supported"))
+ }
+
+ #[cfg(feature = "printing")]
+ fn item_existential(input: ParseStream) -> Result<TokenStream> {
+ use crate::attr::FilterAttrs;
+ use quote::{ToTokens, TokenStreamExt};
+
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let existential_token: existential = input.parse()?;
+ let type_token: Token![type] = input.parse()?;
+ let ident: Ident = input.parse()?;
+
+ let mut generics: Generics = input.parse()?;
+ generics.where_clause = input.parse()?;
+
+ let colon_token: Token![:] = input.parse()?;
+
+ let mut bounds = Punctuated::new();
+ while !input.peek(Token![;]) {
+ if !bounds.is_empty() {
+ bounds.push_punct(input.parse::<Token![+]>()?);
+ }
+ bounds.push_value(input.parse::<TypeParamBound>()?);
+ }
+
+ let semi_token: Token![;] = input.parse()?;
+
+ let mut tokens = TokenStream::new();
+ tokens.append_all(attrs.outer());
+ vis.to_tokens(&mut tokens);
+ existential_token.to_tokens(&mut tokens);
+ type_token.to_tokens(&mut tokens);
+ ident.to_tokens(&mut tokens);
+ generics.to_tokens(&mut tokens);
+ generics.where_clause.to_tokens(&mut tokens);
+ if !bounds.is_empty() {
+ colon_token.to_tokens(&mut tokens);
+ bounds.to_tokens(&mut tokens);
+ }
+ semi_token.to_tokens(&mut tokens);
+ Ok(tokens)
+ }
+
+ impl Parse for ItemStruct {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis = input.parse::<Visibility>()?;
+ let struct_token = input.parse::<Token![struct]>()?;
+ let ident = input.parse::<Ident>()?;
+ let generics = input.parse::<Generics>()?;
+ let (where_clause, fields, semi_token) = derive::parsing::data_struct(input)?;
+ Ok(ItemStruct {
+ attrs,
+ vis,
+ struct_token,
+ ident,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ fields,
+ semi_token,
+ })
+ }
+ }
+
+ impl Parse for ItemEnum {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis = input.parse::<Visibility>()?;
+ let enum_token = input.parse::<Token![enum]>()?;
+ let ident = input.parse::<Ident>()?;
+ let generics = input.parse::<Generics>()?;
+ let (where_clause, brace_token, variants) = derive::parsing::data_enum(input)?;
+ Ok(ItemEnum {
+ attrs,
+ vis,
+ enum_token,
+ ident,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ brace_token,
+ variants,
+ })
+ }
+ }
+
+ impl Parse for ItemUnion {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis = input.parse::<Visibility>()?;
+ let union_token = input.parse::<Token![union]>()?;
+ let ident = input.parse::<Ident>()?;
+ let generics = input.parse::<Generics>()?;
+ let (where_clause, fields) = derive::parsing::data_union(input)?;
+ Ok(ItemUnion {
+ attrs,
+ vis,
+ union_token,
+ ident,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ fields,
+ })
+ }
+ }
+
+ fn parse_trait_or_trait_alias(input: ParseStream) -> Result<Item> {
+ let (attrs, vis, trait_token, ident, generics) = parse_start_of_trait_alias(input)?;
+ let lookahead = input.lookahead1();
+ if lookahead.peek(token::Brace)
+ || lookahead.peek(Token![:])
+ || lookahead.peek(Token![where])
+ {
+ let unsafety = None;
+ let auto_token = None;
+ parse_rest_of_trait(
+ input,
+ attrs,
+ vis,
+ unsafety,
+ auto_token,
+ trait_token,
+ ident,
+ generics,
+ )
+ .map(Item::Trait)
+ } else if lookahead.peek(Token![=]) {
+ parse_rest_of_trait_alias(input, attrs, vis, trait_token, ident, generics)
+ .map(Item::TraitAlias)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+
+ impl Parse for ItemTrait {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let unsafety: Option<Token![unsafe]> = input.parse()?;
+ let auto_token: Option<Token![auto]> = input.parse()?;
+ let trait_token: Token![trait] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let generics: Generics = input.parse()?;
+ parse_rest_of_trait(
+ input,
+ attrs,
+ vis,
+ unsafety,
+ auto_token,
+ trait_token,
+ ident,
+ generics,
+ )
+ }
+ }
+
+ fn parse_rest_of_trait(
+ input: ParseStream,
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ unsafety: Option<Token![unsafe]>,
+ auto_token: Option<Token![auto]>,
+ trait_token: Token![trait],
+ ident: Ident,
+ mut generics: Generics,
+ ) -> Result<ItemTrait> {
+ let colon_token: Option<Token![:]> = input.parse()?;
+
+ let mut supertraits = Punctuated::new();
+ if colon_token.is_some() {
+ loop {
+ supertraits.push_value(input.parse()?);
+ if input.peek(Token![where]) || input.peek(token::Brace) {
+ break;
+ }
+ supertraits.push_punct(input.parse()?);
+ if input.peek(Token![where]) || input.peek(token::Brace) {
+ break;
+ }
+ }
+ }
+
+ generics.where_clause = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let mut items = Vec::new();
+ while !content.is_empty() {
+ items.push(content.parse()?);
+ }
+
+ Ok(ItemTrait {
+ attrs,
+ vis,
+ unsafety,
+ auto_token,
+ trait_token,
+ ident,
+ generics,
+ colon_token,
+ supertraits,
+ brace_token,
+ items,
+ })
+ }
+
+ impl Parse for ItemTraitAlias {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let (attrs, vis, trait_token, ident, generics) = parse_start_of_trait_alias(input)?;
+ parse_rest_of_trait_alias(input, attrs, vis, trait_token, ident, generics)
+ }
+ }
+
+ fn parse_start_of_trait_alias(
+ input: ParseStream,
+ ) -> Result<(Vec<Attribute>, Visibility, Token![trait], Ident, Generics)> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let trait_token: Token![trait] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let generics: Generics = input.parse()?;
+ Ok((attrs, vis, trait_token, ident, generics))
+ }
+
+ fn parse_rest_of_trait_alias(
+ input: ParseStream,
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ trait_token: Token![trait],
+ ident: Ident,
+ mut generics: Generics,
+ ) -> Result<ItemTraitAlias> {
+ let eq_token: Token![=] = input.parse()?;
+
+ let mut bounds = Punctuated::new();
+ loop {
+ if input.peek(Token![where]) || input.peek(Token![;]) {
+ break;
+ }
+ bounds.push_value(input.parse()?);
+ if input.peek(Token![where]) || input.peek(Token![;]) {
+ break;
+ }
+ bounds.push_punct(input.parse()?);
+ }
+
+ generics.where_clause = input.parse()?;
+ let semi_token: Token![;] = input.parse()?;
+
+ Ok(ItemTraitAlias {
+ attrs,
+ vis,
+ trait_token,
+ ident,
+ generics,
+ eq_token,
+ bounds,
+ semi_token,
+ })
+ }
+
+ impl Parse for TraitItem {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut attrs = input.call(Attribute::parse_outer)?;
+ let ahead = input.fork();
+
+ let lookahead = ahead.lookahead1();
+ let mut item = if lookahead.peek(Token![const]) {
+ ahead.parse::<Token![const]>()?;
+ let lookahead = ahead.lookahead1();
+ if lookahead.peek(Ident) {
+ input.parse().map(TraitItem::Const)
+ } else if lookahead.peek(Token![async])
+ || lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ input.parse().map(TraitItem::Method)
+ } else {
+ Err(lookahead.error())
+ }
+ } else if lookahead.peek(Token![async])
+ || lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ input.parse().map(TraitItem::Method)
+ } else if lookahead.peek(Token![type]) {
+ input.parse().map(TraitItem::Type)
+ } else if lookahead.peek(Ident)
+ || lookahead.peek(Token![self])
+ || lookahead.peek(Token![super])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![crate])
+ || lookahead.peek(Token![::])
+ {
+ input.parse().map(TraitItem::Macro)
+ } else {
+ Err(lookahead.error())
+ }?;
+
+ {
+ let item_attrs = match &mut item {
+ TraitItem::Const(item) => &mut item.attrs,
+ TraitItem::Method(item) => &mut item.attrs,
+ TraitItem::Type(item) => &mut item.attrs,
+ TraitItem::Macro(item) => &mut item.attrs,
+ TraitItem::Verbatim(_) | TraitItem::__Nonexhaustive => unreachable!(),
+ };
+ attrs.extend(item_attrs.drain(..));
+ *item_attrs = attrs;
+ }
+
+ Ok(item)
+ }
+ }
+
+ impl Parse for TraitItemConst {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TraitItemConst {
+ attrs: input.call(Attribute::parse_outer)?,
+ const_token: input.parse()?,
+ ident: input.parse()?,
+ colon_token: input.parse()?,
+ ty: input.parse()?,
+ default: {
+ if input.peek(Token![=]) {
+ let eq_token: Token![=] = input.parse()?;
+ let default: Expr = input.parse()?;
+ Some((eq_token, default))
+ } else {
+ None
+ }
+ },
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TraitItemMethod {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+ let constness: Option<Token![const]> = input.parse()?;
+ let asyncness: Option<Token![async]> = input.parse()?;
+ let unsafety: Option<Token![unsafe]> = input.parse()?;
+ let abi: Option<Abi> = input.parse()?;
+ let fn_token: Token![fn] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let generics: Generics = input.parse()?;
+
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let inputs = parse_fn_args(&content)?;
+
+ let output: ReturnType = input.parse()?;
+ let where_clause: Option<WhereClause> = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ let (brace_token, inner_attrs, stmts, semi_token) = if lookahead.peek(token::Brace) {
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+ let stmts = content.call(Block::parse_within)?;
+ (Some(brace_token), inner_attrs, stmts, None)
+ } else if lookahead.peek(Token![;]) {
+ let semi_token: Token![;] = input.parse()?;
+ (None, Vec::new(), Vec::new(), Some(semi_token))
+ } else {
+ return Err(lookahead.error());
+ };
+
+ Ok(TraitItemMethod {
+ attrs: private::attrs(outer_attrs, inner_attrs),
+ sig: Signature {
+ constness,
+ asyncness,
+ unsafety,
+ abi,
+ fn_token,
+ ident,
+ paren_token,
+ inputs,
+ output,
+ variadic: None,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ },
+ default: brace_token.map(|brace_token| Block { brace_token, stmts }),
+ semi_token,
+ })
+ }
+ }
+
+ impl Parse for TraitItemType {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let type_token: Token![type] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let mut generics: Generics = input.parse()?;
+ let colon_token: Option<Token![:]> = input.parse()?;
+
+ let mut bounds = Punctuated::new();
+ if colon_token.is_some() {
+ while !input.peek(Token![where]) && !input.peek(Token![=]) && !input.peek(Token![;])
+ {
+ if !bounds.is_empty() {
+ bounds.push_punct(input.parse()?);
+ }
+ bounds.push_value(input.parse()?);
+ }
+ }
+
+ generics.where_clause = input.parse()?;
+ let default = if input.peek(Token![=]) {
+ let eq_token: Token![=] = input.parse()?;
+ let default: Type = input.parse()?;
+ Some((eq_token, default))
+ } else {
+ None
+ };
+ let semi_token: Token![;] = input.parse()?;
+
+ Ok(TraitItemType {
+ attrs,
+ type_token,
+ ident,
+ generics,
+ colon_token,
+ bounds,
+ default,
+ semi_token,
+ })
+ }
+ }
+
+ impl Parse for TraitItemMacro {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let mac: Macro = input.parse()?;
+ let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() {
+ None
+ } else {
+ Some(input.parse()?)
+ };
+ Ok(TraitItemMacro {
+ attrs,
+ mac,
+ semi_token,
+ })
+ }
+ }
+
+ impl Parse for ItemImpl {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+ let defaultness: Option<Token![default]> = input.parse()?;
+ let unsafety: Option<Token![unsafe]> = input.parse()?;
+ let impl_token: Token![impl] = input.parse()?;
+
+ let has_generics = input.peek(Token![<])
+ && (input.peek2(Token![>])
+ || input.peek2(Token![#])
+ || (input.peek2(Ident) || input.peek2(Lifetime))
+ && (input.peek3(Token![:])
+ || input.peek3(Token![,])
+ || input.peek3(Token![>])));
+ let generics: Generics = if has_generics {
+ input.parse()?
+ } else {
+ Generics::default()
+ };
+
+ let trait_ = (|| -> Option<_> {
+ let ahead = input.fork();
+ let polarity: Option<Token![!]> = ahead.parse().ok()?;
+ let path: Path = ahead.parse().ok()?;
+ let for_token: Token![for] = ahead.parse().ok()?;
+ input.advance_to(&ahead);
+ Some((polarity, path, for_token))
+ })();
+ let self_ty: Type = input.parse()?;
+ let where_clause: Option<WhereClause> = input.parse()?;
+
+ let content;
+ let brace_token = braced!(content in input);
+ let inner_attrs = content.call(Attribute::parse_inner)?;
+
+ let mut items = Vec::new();
+ while !content.is_empty() {
+ items.push(content.parse()?);
+ }
+
+ Ok(ItemImpl {
+ attrs: private::attrs(outer_attrs, inner_attrs),
+ defaultness,
+ unsafety,
+ impl_token,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ trait_,
+ self_ty: Box::new(self_ty),
+ brace_token,
+ items,
+ })
+ }
+ }
+
+ impl Parse for ImplItem {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut attrs = input.call(Attribute::parse_outer)?;
+ let ahead = input.fork();
+ let vis: Visibility = ahead.parse()?;
+
+ let mut lookahead = ahead.lookahead1();
+ let defaultness = if lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) {
+ let defaultness: Token![default] = ahead.parse()?;
+ lookahead = ahead.lookahead1();
+ Some(defaultness)
+ } else {
+ None
+ };
+
+ let mut item = if lookahead.peek(Token![const]) {
+ ahead.parse::<Token![const]>()?;
+ let lookahead = ahead.lookahead1();
+ if lookahead.peek(Ident) {
+ input.parse().map(ImplItem::Const)
+ } else if lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![async])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ input.parse().map(ImplItem::Method)
+ } else {
+ Err(lookahead.error())
+ }
+ } else if lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![async])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![fn])
+ {
+ input.parse().map(ImplItem::Method)
+ } else if lookahead.peek(Token![type]) {
+ input.parse().map(ImplItem::Type)
+ } else if vis.is_inherited() && defaultness.is_none() && lookahead.peek(existential) {
+ input.call(item_existential).map(ImplItem::Verbatim)
+ } else if vis.is_inherited()
+ && defaultness.is_none()
+ && (lookahead.peek(Ident)
+ || lookahead.peek(Token![self])
+ || lookahead.peek(Token![super])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![crate])
+ || lookahead.peek(Token![::]))
+ {
+ input.parse().map(ImplItem::Macro)
+ } else {
+ Err(lookahead.error())
+ }?;
+
+ {
+ let item_attrs = match &mut item {
+ ImplItem::Const(item) => &mut item.attrs,
+ ImplItem::Method(item) => &mut item.attrs,
+ ImplItem::Type(item) => &mut item.attrs,
+ ImplItem::Macro(item) => &mut item.attrs,
+ ImplItem::Verbatim(_) => return Ok(item),
+ ImplItem::__Nonexhaustive => unreachable!(),
+ };
+ attrs.extend(item_attrs.drain(..));
+ *item_attrs = attrs;
+ }
+
+ Ok(item)
+ }
+ }
+
+ impl Parse for ImplItemConst {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ImplItemConst {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ defaultness: input.parse()?,
+ const_token: input.parse()?,
+ ident: input.parse()?,
+ colon_token: input.parse()?,
+ ty: input.parse()?,
+ eq_token: input.parse()?,
+ expr: input.parse()?,
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ImplItemMethod {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let defaultness: Option<Token![default]> = input.parse()?;
+ let constness: Option<Token![const]> = input.parse()?;
+ let asyncness: Option<Token![async]> = input.parse()?;
+ let unsafety: Option<Token![unsafe]> = input.parse()?;
+ let abi: Option<Abi> = input.parse()?;
+ let fn_token: Token![fn] = input.parse()?;
+ let ident: Ident = input.parse()?;
+ let generics: Generics = input.parse()?;
+
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let inputs = parse_fn_args(&content)?;
+
+ let output: ReturnType = input.parse()?;
+ let where_clause: Option<WhereClause> = input.parse()?;
+
+ let block = if let Some(semi) = input.parse::<Option<Token![;]>>()? {
+ // Accept methods without a body in an impl block because
+ // rustc's *parser* does not reject them (the compilation error
+ // is emitted later than parsing) and it can be useful for macro
+ // DSLs.
+ let mut punct = Punct::new(';', Spacing::Alone);
+ punct.set_span(semi.span);
+ let tokens = TokenStream::from_iter(vec![TokenTree::Punct(punct)]);
+ Block {
+ brace_token: Brace::default(),
+ stmts: vec![Stmt::Item(Item::Verbatim(tokens))],
+ }
+ } else {
+ let content;
+ let brace_token = braced!(content in input);
+ attrs.extend(content.call(Attribute::parse_inner)?);
+ Block {
+ brace_token,
+ stmts: content.call(Block::parse_within)?,
+ }
+ };
+
+ Ok(ImplItemMethod {
+ attrs,
+ vis,
+ defaultness,
+ sig: Signature {
+ constness,
+ asyncness,
+ unsafety,
+ abi,
+ fn_token,
+ ident,
+ paren_token,
+ inputs,
+ output,
+ variadic: None,
+ generics: Generics {
+ where_clause,
+ ..generics
+ },
+ },
+ block,
+ })
+ }
+ }
+
+ impl Parse for ImplItemType {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(ImplItemType {
+ attrs: input.call(Attribute::parse_outer)?,
+ vis: input.parse()?,
+ defaultness: input.parse()?,
+ type_token: input.parse()?,
+ ident: input.parse()?,
+ generics: {
+ let mut generics: Generics = input.parse()?;
+ generics.where_clause = input.parse()?;
+ generics
+ },
+ eq_token: input.parse()?,
+ ty: input.parse()?,
+ semi_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ImplItemMacro {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let mac: Macro = input.parse()?;
+ let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() {
+ None
+ } else {
+ Some(input.parse()?)
+ };
+ Ok(ImplItemMacro {
+ attrs,
+ mac,
+ semi_token,
+ })
+ }
+ }
+
+ impl Visibility {
+ fn is_inherited(&self) -> bool {
+ match *self {
+ Visibility::Inherited => true,
+ _ => false,
+ }
+ }
+ }
+
+ impl MacroDelimiter {
+ fn is_brace(&self) -> bool {
+ match *self {
+ MacroDelimiter::Brace(_) => true,
+ MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false,
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ use crate::attr::FilterAttrs;
+ use crate::print::TokensOrDefault;
+
+ impl ToTokens for ItemExternCrate {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.extern_token.to_tokens(tokens);
+ self.crate_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ if let Some((as_token, rename)) = &self.rename {
+ as_token.to_tokens(tokens);
+ rename.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemUse {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.use_token.to_tokens(tokens);
+ self.leading_colon.to_tokens(tokens);
+ self.tree.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemStatic {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.static_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemConst {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.const_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemFn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.sig.to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ impl ToTokens for ItemMod {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.mod_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ if let Some((brace, items)) = &self.content {
+ brace.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(items);
+ });
+ } else {
+ TokensOrDefault(&self.semi).to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for ItemForeignMod {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.abi.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.items);
+ });
+ }
+ }
+
+ impl ToTokens for ItemType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemEnum {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.enum_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ self.variants.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for ItemStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.struct_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ match &self.fields {
+ Fields::Named(fields) => {
+ self.generics.where_clause.to_tokens(tokens);
+ fields.to_tokens(tokens);
+ }
+ Fields::Unnamed(fields) => {
+ fields.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ TokensOrDefault(&self.semi_token).to_tokens(tokens);
+ }
+ Fields::Unit => {
+ self.generics.where_clause.to_tokens(tokens);
+ TokensOrDefault(&self.semi_token).to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for ItemUnion {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.union_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.fields.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemTrait {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.auto_token.to_tokens(tokens);
+ self.trait_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ if !self.supertraits.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.supertraits.to_tokens(tokens);
+ }
+ self.generics.where_clause.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(&self.items);
+ });
+ }
+ }
+
+ impl ToTokens for ItemTraitAlias {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.trait_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemImpl {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.defaultness.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.impl_token.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ if let Some((polarity, path, for_token)) = &self.trait_ {
+ polarity.to_tokens(tokens);
+ path.to_tokens(tokens);
+ for_token.to_tokens(tokens);
+ }
+ self.self_ty.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.items);
+ });
+ }
+ }
+
+ impl ToTokens for ItemMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.path.to_tokens(tokens);
+ self.mac.bang_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ match &self.mac.delimiter {
+ MacroDelimiter::Paren(paren) => {
+ paren.surround(tokens, |tokens| self.mac.tokens.to_tokens(tokens));
+ }
+ MacroDelimiter::Brace(brace) => {
+ brace.surround(tokens, |tokens| self.mac.tokens.to_tokens(tokens));
+ }
+ MacroDelimiter::Bracket(bracket) => {
+ bracket.surround(tokens, |tokens| self.mac.tokens.to_tokens(tokens));
+ }
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemMacro2 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.macro_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.rules.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UsePath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.colon2_token.to_tokens(tokens);
+ self.tree.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UseName {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UseRename {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.as_token.to_tokens(tokens);
+ self.rename.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UseGlob {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.star_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UseGroup {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.brace_token.surround(tokens, |tokens| {
+ self.items.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TraitItemConst {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.const_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ if let Some((eq_token, default)) = &self.default {
+ eq_token.to_tokens(tokens);
+ default.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TraitItemMethod {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.sig.to_tokens(tokens);
+ match &self.default {
+ Some(block) => {
+ block.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&block.stmts);
+ });
+ }
+ None => {
+ TokensOrDefault(&self.semi_token).to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for TraitItemType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ self.generics.where_clause.to_tokens(tokens);
+ if let Some((eq_token, default)) = &self.default {
+ eq_token.to_tokens(tokens);
+ default.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TraitItemMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ImplItemConst {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.defaultness.to_tokens(tokens);
+ self.const_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ImplItemMethod {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.defaultness.to_tokens(tokens);
+ self.sig.to_tokens(tokens);
+ if self.block.stmts.len() == 1 {
+ if let Stmt::Item(Item::Verbatim(verbatim)) = &self.block.stmts[0] {
+ if verbatim.to_string() == ";" {
+ verbatim.to_tokens(tokens);
+ return;
+ }
+ }
+ }
+ self.block.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ impl ToTokens for ImplItemType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.defaultness.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ImplItemMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemFn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.sig.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemStatic {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.static_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ fn has_variadic(inputs: &Punctuated<FnArg, Token![,]>) -> bool {
+ let last = match inputs.last() {
+ Some(last) => last,
+ None => return false,
+ };
+
+ let pat = match last {
+ FnArg::Typed(pat) => pat,
+ FnArg::Receiver(_) => return false,
+ };
+
+ let tokens = match pat.ty.as_ref() {
+ Type::Verbatim(tokens) => tokens,
+ _ => return false,
+ };
+
+ tokens.to_string() == "..."
+ }
+
+ impl ToTokens for Signature {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.constness.to_tokens(tokens);
+ self.asyncness.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.abi.to_tokens(tokens);
+ self.fn_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.inputs.to_tokens(tokens);
+ if self.variadic.is_some() && !has_variadic(&self.inputs) {
+ if !self.inputs.empty_or_trailing() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ self.variadic.to_tokens(tokens);
+ }
+ });
+ self.output.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Receiver {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ if let Some((ampersand, lifetime)) = &self.reference {
+ ampersand.to_tokens(tokens);
+ lifetime.to_tokens(tokens);
+ }
+ self.mutability.to_tokens(tokens);
+ self.self_token.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn/src/keyword.rs b/syn/src/keyword.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/syn/src/keyword.rs
diff --git a/syn/src/lib.rs b/syn/src/lib.rs
new file mode 100644
index 0000000..0f71014
--- /dev/null
+++ b/syn/src/lib.rs
@@ -0,0 +1,947 @@
+//! Syn is a parsing library for parsing a stream of Rust tokens into a syntax
+//! tree of Rust source code.
+//!
+//! Currently this library is geared toward use in Rust procedural macros, but
+//! contains some APIs that may be useful more generally.
+//!
+//! - **Data structures** — Syn provides a complete syntax tree that can
+//! represent any valid Rust source code. The syntax tree is rooted at
+//! [`syn::File`] which represents a full source file, but there are other
+//! entry points that may be useful to procedural macros including
+//! [`syn::Item`], [`syn::Expr`] and [`syn::Type`].
+//!
+//! - **Derives** — Of particular interest to derive macros is
+//! [`syn::DeriveInput`] which is any of the three legal input items to a
+//! derive macro. An example below shows using this type in a library that can
+//! derive implementations of a user-defined trait.
+//!
+//! - **Parsing** — Parsing in Syn is built around [parser functions] with the
+//! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined
+//! by Syn is individually parsable and may be used as a building block for
+//! custom syntaxes, or you may dream up your own brand new syntax without
+//! involving any of our syntax tree types.
+//!
+//! - **Location information** — Every token parsed by Syn is associated with a
+//! `Span` that tracks line and column information back to the source of that
+//! token. These spans allow a procedural macro to display detailed error
+//! messages pointing to all the right places in the user's code. There is an
+//! example of this below.
+//!
+//! - **Feature flags** — Functionality is aggressively feature gated so your
+//! procedural macros enable only what they need, and do not pay in compile
+//! time for all the rest.
+//!
+//! [`syn::File`]: struct.File.html
+//! [`syn::Item`]: enum.Item.html
+//! [`syn::Expr`]: enum.Expr.html
+//! [`syn::Type`]: enum.Type.html
+//! [`syn::DeriveInput`]: struct.DeriveInput.html
+//! [parser functions]: parse/index.html
+//!
+//! <br>
+//!
+//! # Example of a derive macro
+//!
+//! The canonical derive macro using Syn looks like this. We write an ordinary
+//! Rust function tagged with a `proc_macro_derive` attribute and the name of
+//! the trait we are deriving. Any time that derive appears in the user's code,
+//! the Rust compiler passes their data structure as tokens into our macro. We
+//! get to execute arbitrary Rust code to figure out what to do with those
+//! tokens, then hand some tokens back to the compiler to compile into the
+//! user's crate.
+//!
+//! [`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html
+//!
+//! ```toml
+//! [dependencies]
+//! syn = "1.0"
+//! quote = "1.0"
+//!
+//! [lib]
+//! proc-macro = true
+//! ```
+//!
+//! ```
+//! extern crate proc_macro;
+//!
+//! use proc_macro::TokenStream;
+//! use quote::quote;
+//! use syn::{parse_macro_input, DeriveInput};
+//!
+//! # const IGNORE_TOKENS: &str = stringify! {
+//! #[proc_macro_derive(MyMacro)]
+//! # };
+//! pub fn my_macro(input: TokenStream) -> TokenStream {
+//! // Parse the input tokens into a syntax tree
+//! let input = parse_macro_input!(input as DeriveInput);
+//!
+//! // Build the output, possibly using quasi-quotation
+//! let expanded = quote! {
+//! // ...
+//! };
+//!
+//! // Hand the output tokens back to the compiler
+//! TokenStream::from(expanded)
+//! }
+//! ```
+//!
+//! The [`heapsize`] example directory shows a complete working implementation
+//! of a derive macro. It works on any Rust compiler 1.31+. The example derives
+//! a `HeapSize` trait which computes an estimate of the amount of heap memory
+//! owned by a value.
+//!
+//! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize
+//!
+//! ```
+//! pub trait HeapSize {
+//! /// Total number of bytes of heap memory owned by `self`.
+//! fn heap_size_of_children(&self) -> usize;
+//! }
+//! ```
+//!
+//! The derive macro allows users to write `#[derive(HeapSize)]` on data
+//! structures in their program.
+//!
+//! ```
+//! # const IGNORE_TOKENS: &str = stringify! {
+//! #[derive(HeapSize)]
+//! # };
+//! struct Demo<'a, T: ?Sized> {
+//! a: Box<T>,
+//! b: u8,
+//! c: &'a str,
+//! d: String,
+//! }
+//! ```
+//!
+//! <p><br></p>
+//!
+//! # Spans and error reporting
+//!
+//! The token-based procedural macro API provides great control over where the
+//! compiler's error messages are displayed in user code. Consider the error the
+//! user sees if one of their field types does not implement `HeapSize`.
+//!
+//! ```
+//! # const IGNORE_TOKENS: &str = stringify! {
+//! #[derive(HeapSize)]
+//! # };
+//! struct Broken {
+//! ok: String,
+//! bad: std::thread::Thread,
+//! }
+//! ```
+//!
+//! By tracking span information all the way through the expansion of a
+//! procedural macro as shown in the `heapsize` example, token-based macros in
+//! Syn are able to trigger errors that directly pinpoint the source of the
+//! problem.
+//!
+//! ```text
+//! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
+//! --> src/main.rs:7:5
+//! |
+//! 7 | bad: std::thread::Thread,
+//! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread`
+//! ```
+//!
+//! <br>
+//!
+//! # Parsing a custom syntax
+//!
+//! The [`lazy-static`] example directory shows the implementation of a
+//! `functionlike!(...)` procedural macro in which the input tokens are parsed
+//! using Syn's parsing API.
+//!
+//! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static
+//!
+//! The example reimplements the popular `lazy_static` crate from crates.io as a
+//! procedural macro.
+//!
+//! ```
+//! # macro_rules! lazy_static {
+//! # ($($tt:tt)*) => {}
+//! # }
+//! #
+//! lazy_static! {
+//! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
+//! }
+//! ```
+//!
+//! The implementation shows how to trigger custom warnings and error messages
+//! on the macro input.
+//!
+//! ```text
+//! warning: come on, pick a more creative name
+//! --> src/main.rs:10:16
+//! |
+//! 10 | static ref FOO: String = "lazy_static".to_owned();
+//! | ^^^
+//! ```
+//!
+//! <br>
+//!
+//! # Testing
+//!
+//! When testing macros, we often care not just that the macro can be used
+//! successfully but also that when the macro is provided with invalid input it
+//! produces maximally helpful error messages. Consider using the [`trybuild`]
+//! crate to write tests for errors that are emitted by your macro or errors
+//! detected by the Rust compiler in the expanded code following misuse of the
+//! macro. Such tests help avoid regressions from later refactors that
+//! mistakenly make an error no longer trigger or be less helpful than it used
+//! to be.
+//!
+//! [`trybuild`]: https://github.com/dtolnay/trybuild
+//!
+//! <br>
+//!
+//! # Debugging
+//!
+//! When developing a procedural macro it can be helpful to look at what the
+//! generated code looks like. Use `cargo rustc -- -Zunstable-options
+//! --pretty=expanded` or the [`cargo expand`] subcommand.
+//!
+//! [`cargo expand`]: https://github.com/dtolnay/cargo-expand
+//!
+//! To show the expanded code for some crate that uses your procedural macro,
+//! run `cargo expand` from that crate. To show the expanded code for one of
+//! your own test cases, run `cargo expand --test the_test_case` where the last
+//! argument is the name of the test file without the `.rs` extension.
+//!
+//! This write-up by Brandon W Maister discusses debugging in more detail:
+//! [Debugging Rust's new Custom Derive system][debugging].
+//!
+//! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/
+//!
+//! <br>
+//!
+//! # Optional features
+//!
+//! Syn puts a lot of functionality behind optional features in order to
+//! optimize compile time for the most common use cases. The following features
+//! are available.
+//!
+//! - **`derive`** *(enabled by default)* — Data structures for representing the
+//! possible input to a derive macro, including structs and enums and types.
+//! - **`full`** — Data structures for representing the syntax tree of all valid
+//! Rust source code, including items and expressions.
+//! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into
+//! a syntax tree node of a chosen type.
+//! - **`printing`** *(enabled by default)* — Ability to print a syntax tree
+//! node as tokens of Rust source code.
+//! - **`visit`** — Trait for traversing a syntax tree.
+//! - **`visit-mut`** — Trait for traversing and mutating in place a syntax
+//! tree.
+//! - **`fold`** — Trait for transforming an owned syntax tree.
+//! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
+//! types.
+//! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree
+//! types.
+//! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the
+//! dynamic library libproc_macro from rustc toolchain.
+
+// Syn types in rustdoc of other crates get linked to here.
+#![doc(html_root_url = "https://docs.rs/syn/1.0.12")]
+#![deny(clippy::all, clippy::pedantic)]
+// Ignored clippy lints.
+#![allow(
+ clippy::block_in_if_condition_stmt,
+ clippy::cognitive_complexity,
+ clippy::doc_markdown,
+ clippy::eval_order_dependence,
+ clippy::inherent_to_string,
+ clippy::large_enum_variant,
+ clippy::needless_doctest_main,
+ clippy::needless_pass_by_value,
+ clippy::never_loop,
+ clippy::suspicious_op_assign_impl,
+ clippy::too_many_arguments,
+ clippy::trivially_copy_pass_by_ref
+)]
+// Ignored clippy_pedantic lints.
+#![allow(
+ clippy::cast_possible_truncation,
+ clippy::empty_enum,
+ clippy::if_not_else,
+ clippy::items_after_statements,
+ clippy::missing_errors_doc,
+ clippy::module_name_repetitions,
+ clippy::must_use_candidate,
+ clippy::shadow_unrelated,
+ clippy::similar_names,
+ clippy::single_match_else,
+ clippy::too_many_lines,
+ clippy::unseparated_literal_suffix,
+ clippy::use_self,
+ clippy::used_underscore_binding
+)]
+
+#[cfg(all(
+ not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
+ feature = "proc-macro"
+))]
+extern crate proc_macro;
+extern crate proc_macro2;
+extern crate unicode_xid;
+
+#[cfg(feature = "printing")]
+extern crate quote;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+#[macro_use]
+mod macros;
+
+// Not public API.
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[macro_use]
+pub mod group;
+
+#[macro_use]
+pub mod token;
+
+mod ident;
+pub use crate::ident::Ident;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod attr;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::attr::{
+ AttrStyle, Attribute, AttributeArgs, Meta, MetaList, MetaNameValue, NestedMeta,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod bigint;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod data;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::data::{
+ Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, VisRestricted,
+ Visibility,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod expr;
+#[cfg(feature = "full")]
+pub use crate::expr::{
+ Arm, FieldValue, GenericMethodArgument, Label, MethodTurbofish, RangeLimits,
+};
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::expr::{
+ 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, Index, Member,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod generics;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::generics::{
+ BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq,
+ PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound,
+ WhereClause, WherePredicate,
+};
+#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
+pub use crate::generics::{ImplGenerics, Turbofish, TypeGenerics};
+
+#[cfg(feature = "full")]
+mod item;
+#[cfg(feature = "full")]
+pub use crate::item::{
+ 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, Receiver,
+ Signature, TraitItem, TraitItemConst, TraitItemMacro, TraitItemMethod, TraitItemType, UseGlob,
+ UseGroup, UseName, UsePath, UseRename, UseTree,
+};
+
+#[cfg(feature = "full")]
+mod file;
+#[cfg(feature = "full")]
+pub use crate::file::File;
+
+mod lifetime;
+pub use crate::lifetime::Lifetime;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod lit;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::lit::{
+ Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr, StrStyle,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod mac;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::mac::{Macro, MacroDelimiter};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod derive;
+#[cfg(feature = "derive")]
+pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod op;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::op::{BinOp, UnOp};
+
+#[cfg(feature = "full")]
+mod stmt;
+#[cfg(feature = "full")]
+pub use crate::stmt::{Block, Local, Stmt};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod ty;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::ty::{
+ Abi, BareFnArg, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer,
+ TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject,
+ TypeTuple, Variadic,
+};
+
+#[cfg(feature = "full")]
+mod pat;
+#[cfg(feature = "full")]
+pub use crate::pat::{
+ FieldPat, Pat, PatBox, PatIdent, PatLit, PatMacro, PatOr, PatPath, PatRange, PatReference,
+ PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod path;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use crate::path::{
+ AngleBracketedGenericArguments, Binding, Constraint, GenericArgument,
+ ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
+};
+
+#[cfg(feature = "parsing")]
+pub mod buffer;
+#[cfg(feature = "parsing")]
+pub mod ext;
+pub mod punctuated;
+#[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))]
+mod tt;
+
+// Not public API except the `parse_quote!` macro.
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+pub mod parse_quote;
+
+// Not public API except the `parse_macro_input!` macro.
+#[cfg(all(
+ not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
+ feature = "parsing",
+ feature = "proc-macro"
+))]
+#[doc(hidden)]
+pub mod parse_macro_input;
+
+#[cfg(all(feature = "parsing", feature = "printing"))]
+pub mod spanned;
+
+mod gen {
+ /// Syntax tree traversal to walk a shared borrow of a syntax tree.
+ ///
+ /// Each method of the [`Visit`] trait is a hook that can be overridden to
+ /// customize the behavior when visiting the corresponding type of node. By
+ /// default, every method recursively visits the substructure of the input
+ /// by invoking the right visitor method of each of its fields.
+ ///
+ /// [`Visit`]: visit::Visit
+ ///
+ /// ```
+ /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
+ /// #
+ /// pub trait Visit<'ast> {
+ /// /* ... */
+ ///
+ /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) {
+ /// visit_expr_binary(self, node);
+ /// }
+ ///
+ /// /* ... */
+ /// # fn visit_attribute(&mut self, node: &'ast Attribute);
+ /// # fn visit_expr(&mut self, node: &'ast Expr);
+ /// # fn visit_bin_op(&mut self, node: &'ast BinOp);
+ /// }
+ ///
+ /// pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary)
+ /// where
+ /// V: Visit<'ast> + ?Sized,
+ /// {
+ /// for attr in &node.attrs {
+ /// v.visit_attribute(attr);
+ /// }
+ /// v.visit_expr(&*node.left);
+ /// v.visit_bin_op(&node.op);
+ /// v.visit_expr(&*node.right);
+ /// }
+ ///
+ /// /* ... */
+ /// ```
+ ///
+ /// *This module is available if Syn is built with the `"visit"` feature.*
+ ///
+ /// <br>
+ ///
+ /// # Example
+ ///
+ /// This visitor will print the name of every freestanding function in the
+ /// syntax tree, including nested functions.
+ ///
+ /// ```
+ /// // [dependencies]
+ /// // quote = "1.0"
+ /// // syn = { version = "1.0", features = ["full", "visit"] }
+ ///
+ /// use quote::quote;
+ /// use syn::visit::{self, Visit};
+ /// use syn::{File, ItemFn};
+ ///
+ /// struct FnVisitor;
+ ///
+ /// impl<'ast> Visit<'ast> for FnVisitor {
+ /// fn visit_item_fn(&mut self, node: &'ast ItemFn) {
+ /// println!("Function with name={}", node.sig.ident);
+ ///
+ /// // Delegate to the default impl to visit any nested functions.
+ /// visit::visit_item_fn(self, node);
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let code = quote! {
+ /// pub fn f() {
+ /// fn g() {}
+ /// }
+ /// };
+ ///
+ /// let syntax_tree: File = syn::parse2(code).unwrap();
+ /// FnVisitor.visit_file(&syntax_tree);
+ /// }
+ /// ```
+ ///
+ /// The `'ast` lifetime on the input references means that the syntax tree
+ /// outlives the complete recursive visit call, so the visitor is allowed to
+ /// hold on to references into the syntax tree.
+ ///
+ /// ```
+ /// use quote::quote;
+ /// use syn::visit::{self, Visit};
+ /// use syn::{File, ItemFn};
+ ///
+ /// struct FnVisitor<'ast> {
+ /// functions: Vec<&'ast ItemFn>,
+ /// }
+ ///
+ /// impl<'ast> Visit<'ast> for FnVisitor<'ast> {
+ /// fn visit_item_fn(&mut self, node: &'ast ItemFn) {
+ /// self.functions.push(node);
+ /// visit::visit_item_fn(self, node);
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let code = quote! {
+ /// pub fn f() {
+ /// fn g() {}
+ /// }
+ /// };
+ ///
+ /// let syntax_tree: File = syn::parse2(code).unwrap();
+ /// let mut visitor = FnVisitor { functions: Vec::new() };
+ /// visitor.visit_file(&syntax_tree);
+ /// for f in visitor.functions {
+ /// println!("Function with name={}", f.sig.ident);
+ /// }
+ /// }
+ /// ```
+ #[cfg(feature = "visit")]
+ #[rustfmt::skip]
+ pub mod visit;
+
+ /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
+ /// place.
+ ///
+ /// Each method of the [`VisitMut`] trait is a hook that can be overridden
+ /// to customize the behavior when mutating the corresponding type of node.
+ /// By default, every method recursively visits the substructure of the
+ /// input by invoking the right visitor method of each of its fields.
+ ///
+ /// [`VisitMut`]: visit_mut::VisitMut
+ ///
+ /// ```
+ /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
+ /// #
+ /// pub trait VisitMut {
+ /// /* ... */
+ ///
+ /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) {
+ /// visit_expr_binary_mut(self, node);
+ /// }
+ ///
+ /// /* ... */
+ /// # fn visit_attribute_mut(&mut self, node: &mut Attribute);
+ /// # fn visit_expr_mut(&mut self, node: &mut Expr);
+ /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp);
+ /// }
+ ///
+ /// pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary)
+ /// where
+ /// V: VisitMut + ?Sized,
+ /// {
+ /// for attr in &mut node.attrs {
+ /// v.visit_attribute_mut(attr);
+ /// }
+ /// v.visit_expr_mut(&mut *node.left);
+ /// v.visit_bin_op_mut(&mut node.op);
+ /// v.visit_expr_mut(&mut *node.right);
+ /// }
+ ///
+ /// /* ... */
+ /// ```
+ ///
+ /// *This module is available if Syn is built with the `"visit-mut"`
+ /// feature.*
+ ///
+ /// <br>
+ ///
+ /// # Example
+ ///
+ /// This mut visitor replace occurrences of u256 suffixed integer literals
+ /// like `999u256` with a macro invocation `bigint::u256!(999)`.
+ ///
+ /// ```
+ /// // [dependencies]
+ /// // quote = "1.0"
+ /// // syn = { version = "1.0", features = ["full", "visit-mut"] }
+ ///
+ /// use quote::quote;
+ /// use syn::visit_mut::{self, VisitMut};
+ /// use syn::{parse_quote, Expr, File, Lit, LitInt};
+ ///
+ /// struct BigintReplace;
+ ///
+ /// impl VisitMut for BigintReplace {
+ /// fn visit_expr_mut(&mut self, node: &mut Expr) {
+ /// if let Expr::Lit(expr) = &node {
+ /// if let Lit::Int(int) = &expr.lit {
+ /// if int.suffix() == "u256" {
+ /// let digits = int.base10_digits();
+ /// let unsuffixed: LitInt = syn::parse_str(digits).unwrap();
+ /// *node = parse_quote!(bigint::u256!(#unsuffixed));
+ /// return;
+ /// }
+ /// }
+ /// }
+ ///
+ /// // Delegate to the default impl to visit nested expressions.
+ /// visit_mut::visit_expr_mut(self, node);
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let code = quote! {
+ /// fn main() {
+ /// let _ = 999u256;
+ /// }
+ /// };
+ ///
+ /// let mut syntax_tree: File = syn::parse2(code).unwrap();
+ /// BigintReplace.visit_file_mut(&mut syntax_tree);
+ /// println!("{}", quote!(#syntax_tree));
+ /// }
+ /// ```
+ #[cfg(feature = "visit-mut")]
+ #[rustfmt::skip]
+ pub mod visit_mut;
+
+ /// Syntax tree traversal to transform the nodes of an owned syntax tree.
+ ///
+ /// Each method of the [`Fold`] trait is a hook that can be overridden to
+ /// customize the behavior when transforming the corresponding type of node.
+ /// By default, every method recursively visits the substructure of the
+ /// input by invoking the right visitor method of each of its fields.
+ ///
+ /// [`Fold`]: fold::Fold
+ ///
+ /// ```
+ /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
+ /// #
+ /// pub trait Fold {
+ /// /* ... */
+ ///
+ /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary {
+ /// fold_expr_binary(self, node)
+ /// }
+ ///
+ /// /* ... */
+ /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute;
+ /// # fn fold_expr(&mut self, node: Expr) -> Expr;
+ /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp;
+ /// }
+ ///
+ /// pub fn fold_expr_binary<V>(v: &mut V, node: ExprBinary) -> ExprBinary
+ /// where
+ /// V: Fold + ?Sized,
+ /// {
+ /// ExprBinary {
+ /// attrs: node
+ /// .attrs
+ /// .into_iter()
+ /// .map(|attr| v.fold_attribute(attr))
+ /// .collect(),
+ /// left: Box::new(v.fold_expr(*node.left)),
+ /// op: v.fold_bin_op(node.op),
+ /// right: Box::new(v.fold_expr(*node.right)),
+ /// }
+ /// }
+ ///
+ /// /* ... */
+ /// ```
+ ///
+ /// *This module is available if Syn is built with the `"fold"` feature.*
+ ///
+ /// <br>
+ ///
+ /// # Example
+ ///
+ /// This fold inserts parentheses to fully parenthesizes any expression.
+ ///
+ /// ```
+ /// // [dependencies]
+ /// // quote = "1.0"
+ /// // syn = { version = "1.0", features = ["fold", "full"] }
+ ///
+ /// use quote::quote;
+ /// use syn::fold::{fold_expr, Fold};
+ /// use syn::{token, Expr, ExprParen};
+ ///
+ /// struct ParenthesizeEveryExpr;
+ ///
+ /// impl Fold for ParenthesizeEveryExpr {
+ /// fn fold_expr(&mut self, expr: Expr) -> Expr {
+ /// Expr::Paren(ExprParen {
+ /// attrs: Vec::new(),
+ /// expr: Box::new(fold_expr(self, expr)),
+ /// paren_token: token::Paren::default(),
+ /// })
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let code = quote! { a() + b(1) * c.d };
+ /// let expr: Expr = syn::parse2(code).unwrap();
+ /// let parenthesized = ParenthesizeEveryExpr.fold_expr(expr);
+ /// println!("{}", quote!(#parenthesized));
+ ///
+ /// // Output: (((a)()) + (((b)((1))) * ((c).d)))
+ /// }
+ /// ```
+ #[cfg(feature = "fold")]
+ #[rustfmt::skip]
+ pub mod fold;
+
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[path = "../gen_helper.rs"]
+ mod helper;
+}
+pub use crate::gen::*;
+
+// Not public API.
+#[doc(hidden)]
+pub mod export;
+
+mod custom_keyword;
+mod custom_punctuation;
+mod sealed;
+
+#[cfg(feature = "parsing")]
+mod lookahead;
+
+#[cfg(feature = "parsing")]
+pub mod parse;
+
+mod span;
+
+#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
+mod print;
+
+mod thread;
+
+////////////////////////////////////////////////////////////////////////////////
+
+#[allow(dead_code, non_camel_case_types)]
+struct private;
+
+// https://github.com/rust-lang/rust/issues/62830
+#[cfg(feature = "parsing")]
+mod rustdoc_workaround {
+ pub use crate::parse::{self as parse_module};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+mod error;
+pub use crate::error::{Error, Result};
+
+/// Parse tokens of source code into the chosen syntax tree node.
+///
+/// This is preferred over parsing a string because tokens are able to preserve
+/// information about where in the user's code they were originally written (the
+/// "span" of the token), possibly allowing the compiler to produce better error
+/// messages.
+///
+/// This function parses a `proc_macro::TokenStream` which is the type used for
+/// interop with the compiler in a procedural macro. To parse a
+/// `proc_macro2::TokenStream`, use [`syn::parse2`] instead.
+///
+/// [`syn::parse2`]: parse2
+///
+/// *This function is available if Syn is built with both the `"parsing"` and
+/// `"proc-macro"` features.*
+///
+/// # Examples
+///
+/// ```
+/// extern crate proc_macro;
+///
+/// use proc_macro::TokenStream;
+/// use quote::quote;
+/// use syn::DeriveInput;
+///
+/// # const IGNORE_TOKENS: &str = stringify! {
+/// #[proc_macro_derive(MyMacro)]
+/// # };
+/// pub fn my_macro(input: TokenStream) -> TokenStream {
+/// // Parse the tokens into a syntax tree
+/// let ast: DeriveInput = syn::parse(input).unwrap();
+///
+/// // Build the output, possibly using quasi-quotation
+/// let expanded = quote! {
+/// /* ... */
+/// };
+///
+/// // Convert into a token stream and return it
+/// expanded.into()
+/// }
+/// ```
+#[cfg(all(
+ not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
+ feature = "parsing",
+ feature = "proc-macro"
+))]
+pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> {
+ parse::Parser::parse(T::parse, tokens)
+}
+
+/// Parse a proc-macro2 token stream into the chosen syntax tree node.
+///
+/// This function parses a `proc_macro2::TokenStream` which is commonly useful
+/// when the input comes from a node of the Syn syntax tree, for example the
+/// body tokens of a [`Macro`] node. When in a procedural macro parsing the
+/// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`]
+/// instead.
+///
+/// [`syn::parse`]: parse()
+///
+/// *This function is available if Syn is built with the `"parsing"` feature.*
+#[cfg(feature = "parsing")]
+pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {
+ parse::Parser::parse2(T::parse, tokens)
+}
+
+/// Parse a string of Rust code into the chosen syntax tree node.
+///
+/// *This function is available if Syn is built with the `"parsing"` feature.*
+///
+/// # Hygiene
+///
+/// Every span in the resulting syntax tree will be set to resolve at the macro
+/// call site.
+///
+/// # Examples
+///
+/// ```
+/// use syn::{Expr, Result};
+///
+/// fn run() -> Result<()> {
+/// let code = "assert_eq!(u8::max_value(), 255)";
+/// let expr = syn::parse_str::<Expr>(code)?;
+/// println!("{:#?}", expr);
+/// Ok(())
+/// }
+/// #
+/// # run().unwrap();
+/// ```
+#[cfg(feature = "parsing")]
+pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
+ parse::Parser::parse_str(T::parse, s)
+}
+
+// FIXME the name parse_file makes it sound like you might pass in a path to a
+// file, rather than the content.
+/// Parse the content of a file of Rust code.
+///
+/// This is different from `syn::parse_str::<File>(content)` in two ways:
+///
+/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
+/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
+///
+/// If present, either of these would be an error using `from_str`.
+///
+/// *This function is available if Syn is built with the `"parsing"` and
+/// `"full"` features.*
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::error::Error;
+/// use std::fs::File;
+/// use std::io::Read;
+///
+/// fn run() -> Result<(), Box<Error>> {
+/// let mut file = File::open("path/to/code.rs")?;
+/// let mut content = String::new();
+/// file.read_to_string(&mut content)?;
+///
+/// let ast = syn::parse_file(&content)?;
+/// if let Some(shebang) = ast.shebang {
+/// println!("{}", shebang);
+/// }
+/// println!("{} items", ast.items.len());
+///
+/// Ok(())
+/// }
+/// #
+/// # run().unwrap();
+/// ```
+#[cfg(all(feature = "parsing", feature = "full"))]
+pub fn parse_file(mut content: &str) -> Result<File> {
+ // Strip the BOM if it is present
+ const BOM: &str = "\u{feff}";
+ if content.starts_with(BOM) {
+ content = &content[BOM.len()..];
+ }
+
+ let mut shebang = None;
+ if content.starts_with("#!") && !content.starts_with("#![") {
+ if let Some(idx) = content.find('\n') {
+ shebang = Some(content[..idx].to_string());
+ content = &content[idx..];
+ } else {
+ shebang = Some(content.to_string());
+ content = "";
+ }
+ }
+
+ let mut file: File = parse_str(content)?;
+ file.shebang = shebang;
+ Ok(file)
+}
diff --git a/syn/src/lifetime.rs b/syn/src/lifetime.rs
new file mode 100644
index 0000000..d51c48e
--- /dev/null
+++ b/syn/src/lifetime.rs
@@ -0,0 +1,140 @@
+use std::cmp::Ordering;
+use std::fmt::{self, Display};
+use std::hash::{Hash, Hasher};
+
+use proc_macro2::{Ident, Span};
+
+#[cfg(feature = "parsing")]
+use crate::lookahead;
+
+/// A Rust lifetime: `'a`.
+///
+/// Lifetime names must conform to the following rules:
+///
+/// - Must start with an apostrophe.
+/// - Must not consist of just an apostrophe: `'`.
+/// - Character after the apostrophe must be `_` or a Unicode code point with
+/// the XID_Start property.
+/// - All following characters must be Unicode code points with the XID_Continue
+/// property.
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature.*
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Clone)]
+pub struct Lifetime {
+ pub apostrophe: Span,
+ pub ident: Ident,
+}
+
+impl Lifetime {
+ /// # Panics
+ ///
+ /// Panics if the lifetime does not conform to the bulleted rules above.
+ ///
+ /// # Invocation
+ ///
+ /// ```
+ /// # use proc_macro2::Span;
+ /// # use syn::Lifetime;
+ /// #
+ /// # fn f() -> Lifetime {
+ /// Lifetime::new("'a", Span::call_site())
+ /// # }
+ /// ```
+ pub fn new(symbol: &str, span: Span) -> Self {
+ if !symbol.starts_with('\'') {
+ panic!(
+ "lifetime name must start with apostrophe as in \"'a\", got {:?}",
+ symbol
+ );
+ }
+
+ if symbol == "'" {
+ panic!("lifetime name must not be empty");
+ }
+
+ if !crate::ident::xid_ok(&symbol[1..]) {
+ panic!("{:?} is not a valid lifetime name", symbol);
+ }
+
+ Lifetime {
+ apostrophe: span,
+ ident: Ident::new(&symbol[1..], span),
+ }
+ }
+}
+
+impl Display for Lifetime {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ "'".fmt(formatter)?;
+ self.ident.fmt(formatter)
+ }
+}
+
+impl PartialEq for Lifetime {
+ fn eq(&self, other: &Lifetime) -> bool {
+ self.ident.eq(&other.ident)
+ }
+}
+
+impl Eq for Lifetime {}
+
+impl PartialOrd for Lifetime {
+ fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Lifetime {
+ fn cmp(&self, other: &Lifetime) -> Ordering {
+ self.ident.cmp(&other.ident)
+ }
+}
+
+impl Hash for Lifetime {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ self.ident.hash(h)
+ }
+}
+
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[allow(non_snake_case)]
+pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
+ match marker {}
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::parse::{Parse, ParseStream, Result};
+
+ impl Parse for Lifetime {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| {
+ cursor
+ .lifetime()
+ .ok_or_else(|| cursor.error("expected lifetime"))
+ })
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::{Punct, Spacing, TokenStream};
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for Lifetime {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let mut apostrophe = Punct::new('\'', Spacing::Joint);
+ apostrophe.set_span(self.apostrophe);
+ tokens.append(apostrophe);
+ self.ident.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn/src/lit.rs b/syn/src/lit.rs
new file mode 100644
index 0000000..abc4ec2
--- /dev/null
+++ b/syn/src/lit.rs
@@ -0,0 +1,1382 @@
+use proc_macro2::{Literal, Span};
+use std::fmt::{self, Display};
+use std::str::{self, FromStr};
+
+#[cfg(feature = "printing")]
+use proc_macro2::Ident;
+
+#[cfg(feature = "parsing")]
+use proc_macro2::TokenStream;
+
+use proc_macro2::TokenTree;
+
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+
+#[cfg(feature = "parsing")]
+use crate::lookahead;
+#[cfg(feature = "parsing")]
+use crate::parse::{Parse, Parser};
+use crate::{Error, Result};
+
+ast_enum_of_structs! {
+ /// A Rust literal such as a string or integer or boolean.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum Lit #manual_extra_traits {
+ /// A UTF-8 string literal: `"foo"`.
+ Str(LitStr),
+
+ /// A byte string literal: `b"foo"`.
+ ByteStr(LitByteStr),
+
+ /// A byte literal: `b'f'`.
+ Byte(LitByte),
+
+ /// A character literal: `'a'`.
+ Char(LitChar),
+
+ /// An integer literal: `1` or `1u16`.
+ Int(LitInt),
+
+ /// A floating point literal: `1f64` or `1.0e10f64`.
+ ///
+ /// Must be finite. May not be infinte or NaN.
+ Float(LitFloat),
+
+ /// A boolean literal: `true` or `false`.
+ Bool(LitBool),
+
+ /// A raw token literal not interpreted by Syn.
+ Verbatim(Literal),
+ }
+}
+
+ast_struct! {
+ /// A UTF-8 string literal: `"foo"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct LitStr #manual_extra_traits_debug {
+ repr: Box<LitStrRepr>,
+ }
+}
+
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+struct LitStrRepr {
+ token: Literal,
+ suffix: Box<str>,
+}
+
+ast_struct! {
+ /// A byte string literal: `b"foo"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct LitByteStr #manual_extra_traits_debug {
+ token: Literal,
+ }
+}
+
+ast_struct! {
+ /// A byte literal: `b'f'`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct LitByte #manual_extra_traits_debug {
+ token: Literal,
+ }
+}
+
+ast_struct! {
+ /// A character literal: `'a'`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct LitChar #manual_extra_traits_debug {
+ token: Literal,
+ }
+}
+
+ast_struct! {
+ /// An integer literal: `1` or `1u16`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct LitInt #manual_extra_traits_debug {
+ repr: Box<LitIntRepr>,
+ }
+}
+
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+struct LitIntRepr {
+ token: Literal,
+ digits: Box<str>,
+ suffix: Box<str>,
+}
+
+ast_struct! {
+ /// A floating point literal: `1f64` or `1.0e10f64`.
+ ///
+ /// Must be finite. May not be infinte or NaN.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct LitFloat #manual_extra_traits_debug {
+ repr: Box<LitFloatRepr>,
+ }
+}
+
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+struct LitFloatRepr {
+ token: Literal,
+ digits: Box<str>,
+ suffix: Box<str>,
+}
+
+ast_struct! {
+ /// A boolean literal: `true` or `false`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct LitBool #manual_extra_traits_debug {
+ pub value: bool,
+ pub span: Span,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Lit {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Lit {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Lit::Str(this), Lit::Str(other)) => this == other,
+ (Lit::ByteStr(this), Lit::ByteStr(other)) => this == other,
+ (Lit::Byte(this), Lit::Byte(other)) => this == other,
+ (Lit::Char(this), Lit::Char(other)) => this == other,
+ (Lit::Int(this), Lit::Int(other)) => this == other,
+ (Lit::Float(this), Lit::Float(other)) => this == other,
+ (Lit::Bool(this), Lit::Bool(other)) => this == other,
+ (Lit::Verbatim(this), Lit::Verbatim(other)) => this.to_string() == other.to_string(),
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Lit {
+ fn hash<H>(&self, hash: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ Lit::Str(lit) => {
+ hash.write_u8(0);
+ lit.hash(hash);
+ }
+ Lit::ByteStr(lit) => {
+ hash.write_u8(1);
+ lit.hash(hash);
+ }
+ Lit::Byte(lit) => {
+ hash.write_u8(2);
+ lit.hash(hash);
+ }
+ Lit::Char(lit) => {
+ hash.write_u8(3);
+ lit.hash(hash);
+ }
+ Lit::Int(lit) => {
+ hash.write_u8(4);
+ lit.hash(hash);
+ }
+ Lit::Float(lit) => {
+ hash.write_u8(5);
+ lit.hash(hash);
+ }
+ Lit::Bool(lit) => {
+ hash.write_u8(6);
+ lit.hash(hash);
+ }
+ Lit::Verbatim(lit) => {
+ hash.write_u8(7);
+ lit.to_string().hash(hash);
+ }
+ }
+ }
+}
+
+impl LitStr {
+ pub fn new(value: &str, span: Span) -> Self {
+ let mut lit = Literal::string(value);
+ lit.set_span(span);
+ LitStr {
+ repr: Box::new(LitStrRepr {
+ token: lit,
+ suffix: Box::<str>::default(),
+ }),
+ }
+ }
+
+ pub fn value(&self) -> String {
+ let (value, _) = value::parse_lit_str(&self.repr.token.to_string());
+ String::from(value)
+ }
+
+ /// Parse a syntax tree node from the content of this string literal.
+ ///
+ /// All spans in the syntax tree will point to the span of this `LitStr`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use proc_macro2::Span;
+ /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
+ ///
+ /// // Parses the path from an attribute that looks like:
+ /// //
+ /// // #[path = "a::b::c"]
+ /// //
+ /// // or returns `None` if the input is some other attribute.
+ /// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
+ /// if !attr.path.is_ident("path") {
+ /// return Ok(None);
+ /// }
+ ///
+ /// match attr.parse_meta()? {
+ /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => {
+ /// lit_str.parse().map(Some)
+ /// }
+ /// _ => {
+ /// let message = "expected #[path = \"...\"]";
+ /// Err(Error::new_spanned(attr, message))
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[cfg(feature = "parsing")]
+ pub fn parse<T: Parse>(&self) -> Result<T> {
+ self.parse_with(T::parse)
+ }
+
+ /// Invoke parser on the content of this string literal.
+ ///
+ /// All spans in the syntax tree will point to the span of this `LitStr`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use proc_macro2::Span;
+ /// # use syn::{LitStr, Result};
+ /// #
+ /// # fn main() -> Result<()> {
+ /// # let lit_str = LitStr::new("a::b::c", Span::call_site());
+ /// #
+ /// # const IGNORE: &str = stringify! {
+ /// let lit_str: LitStr = /* ... */;
+ /// # };
+ ///
+ /// // Parse a string literal like "a::b::c" into a Path, not allowing
+ /// // generic arguments on any of the path segments.
+ /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?;
+ /// #
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[cfg(feature = "parsing")]
+ pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
+ use proc_macro2::Group;
+
+ // Token stream with every span replaced by the given one.
+ fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
+ stream
+ .into_iter()
+ .map(|token| respan_token_tree(token, span))
+ .collect()
+ }
+
+ // Token tree with every span replaced by the given one.
+ fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
+ match &mut token {
+ TokenTree::Group(g) => {
+ let stream = respan_token_stream(g.stream(), span);
+ *g = Group::new(g.delimiter(), stream);
+ g.set_span(span);
+ }
+ other => other.set_span(span),
+ }
+ token
+ }
+
+ // Parse string literal into a token stream with every span equal to the
+ // original literal's span.
+ let mut tokens = crate::parse_str(&self.value())?;
+ tokens = respan_token_stream(tokens, self.span());
+
+ parser.parse2(tokens)
+ }
+
+ pub fn span(&self) -> Span {
+ self.repr.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.repr.token.set_span(span)
+ }
+
+ pub fn suffix(&self) -> &str {
+ &self.repr.suffix
+ }
+}
+
+impl LitByteStr {
+ pub fn new(value: &[u8], span: Span) -> Self {
+ let mut token = Literal::byte_string(value);
+ token.set_span(span);
+ LitByteStr { token }
+ }
+
+ pub fn value(&self) -> Vec<u8> {
+ value::parse_lit_byte_str(&self.token.to_string())
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+impl LitByte {
+ pub fn new(value: u8, span: Span) -> Self {
+ let mut token = Literal::u8_suffixed(value);
+ token.set_span(span);
+ LitByte { token }
+ }
+
+ pub fn value(&self) -> u8 {
+ value::parse_lit_byte(&self.token.to_string())
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+impl LitChar {
+ pub fn new(value: char, span: Span) -> Self {
+ let mut token = Literal::character(value);
+ token.set_span(span);
+ LitChar { token }
+ }
+
+ pub fn value(&self) -> char {
+ value::parse_lit_char(&self.token.to_string())
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+impl LitInt {
+ pub fn new(repr: &str, span: Span) -> Self {
+ if let Some((digits, suffix)) = value::parse_lit_int(repr) {
+ let mut token = value::to_literal(repr);
+ token.set_span(span);
+ LitInt {
+ repr: Box::new(LitIntRepr {
+ token,
+ digits,
+ suffix,
+ }),
+ }
+ } else {
+ panic!("Not an integer literal: `{}`", repr);
+ }
+ }
+
+ pub fn base10_digits(&self) -> &str {
+ &self.repr.digits
+ }
+
+ /// Parses the literal into a selected number type.
+ ///
+ /// This is equivalent to `lit.base10_digits().parse()` except that the
+ /// resulting errors will be correctly spanned to point to the literal token
+ /// in the macro input.
+ ///
+ /// ```
+ /// use syn::LitInt;
+ /// use syn::parse::{Parse, ParseStream, Result};
+ ///
+ /// struct Port {
+ /// value: u16,
+ /// }
+ ///
+ /// impl Parse for Port {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// let lit: LitInt = input.parse()?;
+ /// let value = lit.base10_parse::<u16>()?;
+ /// Ok(Port { value })
+ /// }
+ /// }
+ /// ```
+ pub fn base10_parse<N>(&self) -> Result<N>
+ where
+ N: FromStr,
+ N::Err: Display,
+ {
+ self.base10_digits()
+ .parse()
+ .map_err(|err| Error::new(self.span(), err))
+ }
+
+ pub fn suffix(&self) -> &str {
+ &self.repr.suffix
+ }
+
+ pub fn span(&self) -> Span {
+ self.repr.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.repr.token.set_span(span)
+ }
+}
+
+impl From<Literal> for LitInt {
+ fn from(token: Literal) -> Self {
+ let repr = token.to_string();
+ if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
+ LitInt {
+ repr: Box::new(LitIntRepr {
+ token,
+ digits,
+ suffix,
+ }),
+ }
+ } else {
+ panic!("Not an integer literal: `{}`", repr);
+ }
+ }
+}
+
+impl Display for LitInt {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ self.repr.token.fmt(formatter)
+ }
+}
+
+impl LitFloat {
+ pub fn new(repr: &str, span: Span) -> Self {
+ if let Some((digits, suffix)) = value::parse_lit_float(repr) {
+ let mut token = value::to_literal(repr);
+ token.set_span(span);
+ LitFloat {
+ repr: Box::new(LitFloatRepr {
+ token,
+ digits,
+ suffix,
+ }),
+ }
+ } else {
+ panic!("Not a float literal: `{}`", repr);
+ }
+ }
+
+ pub fn base10_digits(&self) -> &str {
+ &self.repr.digits
+ }
+
+ pub fn base10_parse<N>(&self) -> Result<N>
+ where
+ N: FromStr,
+ N::Err: Display,
+ {
+ self.base10_digits()
+ .parse()
+ .map_err(|err| Error::new(self.span(), err))
+ }
+
+ pub fn suffix(&self) -> &str {
+ &self.repr.suffix
+ }
+
+ pub fn span(&self) -> Span {
+ self.repr.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.repr.token.set_span(span)
+ }
+}
+
+impl From<Literal> for LitFloat {
+ fn from(token: Literal) -> Self {
+ let repr = token.to_string();
+ if let Some((digits, suffix)) = value::parse_lit_float(&repr) {
+ LitFloat {
+ repr: Box::new(LitFloatRepr {
+ token,
+ digits,
+ suffix,
+ }),
+ }
+ } else {
+ panic!("Not a float literal: `{}`", repr);
+ }
+ }
+}
+
+impl Display for LitFloat {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ self.repr.token.fmt(formatter)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+mod debug_impls {
+ use super::*;
+ use std::fmt::{self, Debug};
+
+ impl Debug for LitStr {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_struct("LitStr")
+ .field("token", &format_args!("{}", self.repr.token))
+ .finish()
+ }
+ }
+
+ impl Debug for LitByteStr {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_struct("LitByteStr")
+ .field("token", &format_args!("{}", self.token))
+ .finish()
+ }
+ }
+
+ impl Debug for LitByte {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_struct("LitByte")
+ .field("token", &format_args!("{}", self.token))
+ .finish()
+ }
+ }
+
+ impl Debug for LitChar {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_struct("LitChar")
+ .field("token", &format_args!("{}", self.token))
+ .finish()
+ }
+ }
+
+ impl Debug for LitInt {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_struct("LitInt")
+ .field("token", &format_args!("{}", self.repr.token))
+ .finish()
+ }
+ }
+
+ impl Debug for LitFloat {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_struct("LitFloat")
+ .field("token", &format_args!("{}", self.repr.token))
+ .finish()
+ }
+ }
+
+ impl Debug for LitBool {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_struct("LitBool")
+ .field("value", &self.value)
+ .finish()
+ }
+ }
+}
+
+macro_rules! lit_extra_traits {
+ ($ty:ident, $($field:ident).+) => {
+ #[cfg(feature = "extra-traits")]
+ impl Eq for $ty {}
+
+ #[cfg(feature = "extra-traits")]
+ impl PartialEq for $ty {
+ fn eq(&self, other: &Self) -> bool {
+ self.$($field).+.to_string() == other.$($field).+.to_string()
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl Hash for $ty {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.$($field).+.to_string().hash(state);
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
+ match marker {}
+ }
+ };
+}
+
+lit_extra_traits!(LitStr, repr.token);
+lit_extra_traits!(LitByteStr, token);
+lit_extra_traits!(LitByte, token);
+lit_extra_traits!(LitChar, token);
+lit_extra_traits!(LitInt, repr.token);
+lit_extra_traits!(LitFloat, repr.token);
+lit_extra_traits!(LitBool, value);
+
+ast_enum! {
+ /// The style of a string literal, either plain quoted or a raw string like
+ /// `r##"data"##`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum StrStyle #no_visit {
+ /// An ordinary string like `"data"`.
+ Cooked,
+ /// A raw string like `r##"data"##`.
+ ///
+ /// The unsigned integer is the number of `#` symbols used.
+ Raw(usize),
+ }
+}
+
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[allow(non_snake_case)]
+pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
+ match marker {}
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use crate::parse::{Parse, ParseStream, Result};
+
+ impl Parse for Lit {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| {
+ if let Some((lit, rest)) = cursor.literal() {
+ return Ok((Lit::new(lit), rest));
+ }
+ while let Some((ident, rest)) = cursor.ident() {
+ let value = if ident == "true" {
+ true
+ } else if ident == "false" {
+ false
+ } else {
+ break;
+ };
+ let lit_bool = LitBool {
+ value,
+ span: ident.span(),
+ };
+ return Ok((Lit::Bool(lit_bool), rest));
+ }
+ Err(cursor.error("expected literal"))
+ })
+ }
+ }
+
+ impl Parse for LitStr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Str(lit) => Ok(lit),
+ _ => Err(head.error("expected string literal")),
+ }
+ }
+ }
+
+ impl Parse for LitByteStr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::ByteStr(lit) => Ok(lit),
+ _ => Err(head.error("expected byte string literal")),
+ }
+ }
+ }
+
+ impl Parse for LitByte {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Byte(lit) => Ok(lit),
+ _ => Err(head.error("expected byte literal")),
+ }
+ }
+ }
+
+ impl Parse for LitChar {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Char(lit) => Ok(lit),
+ _ => Err(head.error("expected character literal")),
+ }
+ }
+ }
+
+ impl Parse for LitInt {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Int(lit) => Ok(lit),
+ _ => Err(head.error("expected integer literal")),
+ }
+ }
+ }
+
+ impl Parse for LitFloat {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Float(lit) => Ok(lit),
+ _ => Err(head.error("expected floating point literal")),
+ }
+ }
+ }
+
+ impl Parse for LitBool {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let head = input.fork();
+ match input.parse()? {
+ Lit::Bool(lit) => Ok(lit),
+ _ => Err(head.error("expected boolean literal")),
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for LitStr {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.repr.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitByteStr {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitByte {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitChar {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitInt {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.repr.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitFloat {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.repr.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitBool {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let s = if self.value { "true" } else { "false" };
+ tokens.append(Ident::new(s, self.span));
+ }
+ }
+}
+
+mod value {
+ use super::*;
+ use crate::bigint::BigInt;
+ use proc_macro2::TokenStream;
+ use std::char;
+ use std::ops::{Index, RangeFrom};
+
+ impl Lit {
+ /// Interpret a Syn literal from a proc-macro2 literal.
+ pub fn new(token: Literal) -> Self {
+ let repr = token.to_string();
+
+ match byte(&repr, 0) {
+ b'"' | b'r' => {
+ let (_, suffix) = parse_lit_str(&repr);
+ return Lit::Str(LitStr {
+ repr: Box::new(LitStrRepr { token, suffix }),
+ });
+ }
+ b'b' => match byte(&repr, 1) {
+ b'"' | b'r' => {
+ return Lit::ByteStr(LitByteStr { token });
+ }
+ b'\'' => {
+ return Lit::Byte(LitByte { token });
+ }
+ _ => {}
+ },
+ b'\'' => {
+ return Lit::Char(LitChar { token });
+ }
+ b'0'..=b'9' | b'-' => {
+ if !(repr.ends_with("f32") || repr.ends_with("f64")) {
+ if let Some((digits, suffix)) = parse_lit_int(&repr) {
+ return Lit::Int(LitInt {
+ repr: Box::new(LitIntRepr {
+ token,
+ digits,
+ suffix,
+ }),
+ });
+ }
+ }
+ if let Some((digits, suffix)) = parse_lit_float(&repr) {
+ return Lit::Float(LitFloat {
+ repr: Box::new(LitFloatRepr {
+ token,
+ digits,
+ suffix,
+ }),
+ });
+ }
+ }
+ b't' | b'f' => {
+ if repr == "true" || repr == "false" {
+ return Lit::Bool(LitBool {
+ value: repr == "true",
+ span: token.span(),
+ });
+ }
+ }
+ _ => {}
+ }
+
+ panic!("Unrecognized literal: `{}`", repr);
+ }
+ }
+
+ /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
+ /// past the end of the input buffer.
+ pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
+ let s = s.as_ref();
+ if idx < s.len() {
+ s[idx]
+ } else {
+ 0
+ }
+ }
+
+ fn next_chr(s: &str) -> char {
+ s.chars().next().unwrap_or('\0')
+ }
+
+ // Returns (content, suffix).
+ pub fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
+ match byte(s, 0) {
+ b'"' => parse_lit_str_cooked(s),
+ b'r' => parse_lit_str_raw(s),
+ _ => unreachable!(),
+ }
+ }
+
+ // Clippy false positive
+ // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
+ #[allow(clippy::needless_continue)]
+ fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) {
+ assert_eq!(byte(s, 0), b'"');
+ s = &s[1..];
+
+ let mut content = String::new();
+ 'outer: loop {
+ let ch = match byte(s, 0) {
+ b'"' => break,
+ b'\\' => {
+ let b = byte(s, 1);
+ s = &s[2..];
+ match b {
+ b'x' => {
+ let (byte, rest) = backslash_x(s);
+ s = rest;
+ assert!(byte <= 0x80, "Invalid \\x byte in string literal");
+ char::from_u32(u32::from(byte)).unwrap()
+ }
+ b'u' => {
+ let (chr, rest) = backslash_u(s);
+ s = rest;
+ chr
+ }
+ b'n' => '\n',
+ b'r' => '\r',
+ b't' => '\t',
+ b'\\' => '\\',
+ b'0' => '\0',
+ b'\'' => '\'',
+ b'"' => '"',
+ b'\r' | b'\n' => loop {
+ let ch = next_chr(s);
+ if ch.is_whitespace() {
+ s = &s[ch.len_utf8()..];
+ } else {
+ continue 'outer;
+ }
+ },
+ b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
+ }
+ }
+ b'\r' => {
+ assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
+ s = &s[2..];
+ '\n'
+ }
+ _ => {
+ let ch = next_chr(s);
+ s = &s[ch.len_utf8()..];
+ ch
+ }
+ };
+ content.push(ch);
+ }
+
+ assert!(s.starts_with('"'));
+ let content = content.into_boxed_str();
+ let suffix = s[1..].to_owned().into_boxed_str();
+ (content, suffix)
+ }
+
+ fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) {
+ assert_eq!(byte(s, 0), b'r');
+ s = &s[1..];
+
+ let mut pounds = 0;
+ while byte(s, pounds) == b'#' {
+ pounds += 1;
+ }
+ assert_eq!(byte(s, pounds), b'"');
+ assert_eq!(byte(s, s.len() - pounds - 1), b'"');
+ for end in s[s.len() - pounds..].bytes() {
+ assert_eq!(end, b'#');
+ }
+
+ let content = s[pounds + 1..s.len() - pounds - 1]
+ .to_owned()
+ .into_boxed_str();
+ let suffix = Box::<str>::default(); // todo
+ (content, suffix)
+ }
+
+ pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
+ assert_eq!(byte(s, 0), b'b');
+ match byte(s, 1) {
+ b'"' => parse_lit_byte_str_cooked(s),
+ b'r' => parse_lit_byte_str_raw(s),
+ _ => unreachable!(),
+ }
+ }
+
+ // Clippy false positive
+ // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
+ #[allow(clippy::needless_continue)]
+ fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
+ assert_eq!(byte(s, 0), b'b');
+ assert_eq!(byte(s, 1), b'"');
+ s = &s[2..];
+
+ // We're going to want to have slices which don't respect codepoint boundaries.
+ let mut s = s.as_bytes();
+
+ let mut out = Vec::new();
+ 'outer: loop {
+ let byte = match byte(s, 0) {
+ b'"' => break,
+ b'\\' => {
+ let b = byte(s, 1);
+ s = &s[2..];
+ match b {
+ b'x' => {
+ let (b, rest) = backslash_x(s);
+ s = rest;
+ b
+ }
+ b'n' => b'\n',
+ b'r' => b'\r',
+ b't' => b'\t',
+ b'\\' => b'\\',
+ b'0' => b'\0',
+ b'\'' => b'\'',
+ b'"' => b'"',
+ b'\r' | b'\n' => loop {
+ let byte = byte(s, 0);
+ let ch = char::from_u32(u32::from(byte)).unwrap();
+ if ch.is_whitespace() {
+ s = &s[1..];
+ } else {
+ continue 'outer;
+ }
+ },
+ b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
+ }
+ }
+ b'\r' => {
+ assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
+ s = &s[2..];
+ b'\n'
+ }
+ b => {
+ s = &s[1..];
+ b
+ }
+ };
+ out.push(byte);
+ }
+
+ assert_eq!(s, b"\"");
+ out
+ }
+
+ fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
+ assert_eq!(byte(s, 0), b'b');
+ String::from(parse_lit_str_raw(&s[1..]).0).into_bytes()
+ }
+
+ pub fn parse_lit_byte(s: &str) -> u8 {
+ assert_eq!(byte(s, 0), b'b');
+ assert_eq!(byte(s, 1), b'\'');
+
+ // We're going to want to have slices which don't respect codepoint boundaries.
+ let mut s = s[2..].as_bytes();
+
+ let b = match byte(s, 0) {
+ b'\\' => {
+ let b = byte(s, 1);
+ s = &s[2..];
+ match b {
+ b'x' => {
+ let (b, rest) = backslash_x(s);
+ s = rest;
+ b
+ }
+ b'n' => b'\n',
+ b'r' => b'\r',
+ b't' => b'\t',
+ b'\\' => b'\\',
+ b'0' => b'\0',
+ b'\'' => b'\'',
+ b'"' => b'"',
+ b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
+ }
+ }
+ b => {
+ s = &s[1..];
+ b
+ }
+ };
+
+ assert_eq!(byte(s, 0), b'\'');
+ b
+ }
+
+ pub fn parse_lit_char(mut s: &str) -> char {
+ assert_eq!(byte(s, 0), b'\'');
+ s = &s[1..];
+
+ let ch = match byte(s, 0) {
+ b'\\' => {
+ let b = byte(s, 1);
+ s = &s[2..];
+ match b {
+ b'x' => {
+ let (byte, rest) = backslash_x(s);
+ s = rest;
+ assert!(byte <= 0x80, "Invalid \\x byte in string literal");
+ char::from_u32(u32::from(byte)).unwrap()
+ }
+ b'u' => {
+ let (chr, rest) = backslash_u(s);
+ s = rest;
+ chr
+ }
+ b'n' => '\n',
+ b'r' => '\r',
+ b't' => '\t',
+ b'\\' => '\\',
+ b'0' => '\0',
+ b'\'' => '\'',
+ b'"' => '"',
+ b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
+ }
+ }
+ _ => {
+ let ch = next_chr(s);
+ s = &s[ch.len_utf8()..];
+ ch
+ }
+ };
+ assert_eq!(s, "\'", "Expected end of char literal");
+ ch
+ }
+
+ fn backslash_x<S>(s: &S) -> (u8, &S)
+ where
+ S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
+ {
+ let mut ch = 0;
+ let b0 = byte(s, 0);
+ let b1 = byte(s, 1);
+ ch += 0x10
+ * match b0 {
+ b'0'..=b'9' => b0 - b'0',
+ b'a'..=b'f' => 10 + (b0 - b'a'),
+ b'A'..=b'F' => 10 + (b0 - b'A'),
+ _ => panic!("unexpected non-hex character after \\x"),
+ };
+ ch += match b1 {
+ b'0'..=b'9' => b1 - b'0',
+ b'a'..=b'f' => 10 + (b1 - b'a'),
+ b'A'..=b'F' => 10 + (b1 - b'A'),
+ _ => panic!("unexpected non-hex character after \\x"),
+ };
+ (ch, &s[2..])
+ }
+
+ fn backslash_u(mut s: &str) -> (char, &str) {
+ if byte(s, 0) != b'{' {
+ panic!("expected {{ after \\u");
+ }
+ s = &s[1..];
+
+ let mut ch = 0;
+ for _ in 0..6 {
+ let b = byte(s, 0);
+ match b {
+ b'0'..=b'9' => {
+ ch *= 0x10;
+ ch += u32::from(b - b'0');
+ s = &s[1..];
+ }
+ b'a'..=b'f' => {
+ ch *= 0x10;
+ ch += u32::from(10 + b - b'a');
+ s = &s[1..];
+ }
+ b'A'..=b'F' => {
+ ch *= 0x10;
+ ch += u32::from(10 + b - b'A');
+ s = &s[1..];
+ }
+ b'}' => break,
+ _ => panic!("unexpected non-hex character after \\u"),
+ }
+ }
+ assert!(byte(s, 0) == b'}');
+ s = &s[1..];
+
+ if let Some(ch) = char::from_u32(ch) {
+ (ch, s)
+ } else {
+ panic!("character code {:x} is not a valid unicode character", ch);
+ }
+ }
+
+ // Returns base 10 digits and suffix.
+ pub fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
+ let negative = byte(s, 0) == b'-';
+ if negative {
+ s = &s[1..];
+ }
+
+ let base = match (byte(s, 0), byte(s, 1)) {
+ (b'0', b'x') => {
+ s = &s[2..];
+ 16
+ }
+ (b'0', b'o') => {
+ s = &s[2..];
+ 8
+ }
+ (b'0', b'b') => {
+ s = &s[2..];
+ 2
+ }
+ (b'0'..=b'9', _) => 10,
+ _ => return None,
+ };
+
+ let mut value = BigInt::new();
+ loop {
+ let b = byte(s, 0);
+ let digit = match b {
+ b'0'..=b'9' => b - b'0',
+ b'a'..=b'f' if base > 10 => b - b'a' + 10,
+ b'A'..=b'F' if base > 10 => b - b'A' + 10,
+ b'_' => {
+ s = &s[1..];
+ continue;
+ }
+ // NOTE: Looking at a floating point literal, we don't want to
+ // consider these integers.
+ b'.' if base == 10 => return None,
+ b'e' | b'E' if base == 10 => return None,
+ _ => break,
+ };
+
+ if digit >= base {
+ return None;
+ }
+
+ value *= base;
+ value += digit;
+ s = &s[1..];
+ }
+
+ let suffix = s;
+ if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
+ let mut repr = value.to_string();
+ if negative {
+ repr.insert(0, '-');
+ }
+ Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str()))
+ } else {
+ None
+ }
+ }
+
+ // Returns base 10 digits and suffix.
+ pub fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
+ // Rust's floating point literals are very similar to the ones parsed by
+ // the standard library, except that rust's literals can contain
+ // ignorable underscores. Let's remove those underscores.
+
+ let mut bytes = input.to_owned().into_bytes();
+
+ let start = (*bytes.get(0)? == b'-') as usize;
+ match bytes.get(start)? {
+ b'0'..=b'9' => {}
+ _ => return None,
+ }
+
+ let mut read = start;
+ let mut write = start;
+ let mut has_dot = false;
+ let mut has_e = false;
+ let mut has_sign = false;
+ let mut has_exponent = false;
+ while read < bytes.len() {
+ match bytes[read] {
+ b'_' => {
+ // Don't increase write
+ read += 1;
+ continue;
+ }
+ b'0'..=b'9' => {
+ if has_e {
+ has_exponent = true;
+ }
+ bytes[write] = bytes[read];
+ }
+ b'.' => {
+ if has_e || has_dot {
+ return None;
+ }
+ has_dot = true;
+ bytes[write] = b'.';
+ }
+ b'e' | b'E' => {
+ if has_e {
+ return None;
+ }
+ has_e = true;
+ bytes[write] = b'e';
+ }
+ b'-' | b'+' => {
+ if has_sign || has_exponent || !has_e {
+ return None;
+ }
+ has_sign = true;
+ if bytes[read] == b'-' {
+ bytes[write] = bytes[read];
+ } else {
+ // Omit '+'
+ read += 1;
+ continue;
+ }
+ }
+ _ => break,
+ }
+ read += 1;
+ write += 1;
+ }
+
+ if has_e && !has_exponent {
+ return None;
+ }
+
+ let mut digits = String::from_utf8(bytes).unwrap();
+ let suffix = digits.split_off(read);
+ digits.truncate(write);
+ if suffix.is_empty() || crate::ident::xid_ok(&suffix) {
+ Some((digits.into_boxed_str(), suffix.into_boxed_str()))
+ } else {
+ None
+ }
+ }
+
+ pub fn to_literal(s: &str) -> Literal {
+ let stream = s.parse::<TokenStream>().unwrap();
+ match stream.into_iter().next().unwrap() {
+ TokenTree::Literal(l) => l,
+ _ => unreachable!(),
+ }
+ }
+}
diff --git a/syn/src/lookahead.rs b/syn/src/lookahead.rs
new file mode 100644
index 0000000..6a67909
--- /dev/null
+++ b/syn/src/lookahead.rs
@@ -0,0 +1,168 @@
+use std::cell::RefCell;
+
+use proc_macro2::{Delimiter, Span};
+
+use crate::buffer::Cursor;
+use crate::error::{self, Error};
+use crate::sealed::lookahead::Sealed;
+use crate::span::IntoSpans;
+use crate::token::Token;
+
+/// Support for checking the next token in a stream to decide how to parse.
+///
+/// An important advantage over [`ParseStream::peek`] is that here we
+/// automatically construct an appropriate error message based on the token
+/// alternatives that get peeked. If you are producing your own error message,
+/// go ahead and use `ParseStream::peek` instead.
+///
+/// Use [`ParseStream::lookahead1`] to construct this object.
+///
+/// [`ParseStream::peek`]: crate::parse::ParseBuffer::peek
+/// [`ParseStream::lookahead1`]: crate::parse::ParseBuffer::lookahead1
+///
+/// # Example
+///
+/// ```
+/// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, Token, TypeParam};
+/// use syn::parse::{Parse, ParseStream};
+///
+/// // A generic parameter, a single one of the comma-separated elements inside
+/// // angle brackets in:
+/// //
+/// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... }
+/// //
+/// // On invalid input, lookahead gives us a reasonable error message.
+/// //
+/// // error: expected one of: identifier, lifetime, `const`
+/// // |
+/// // 5 | fn f<!Sized>() {}
+/// // | ^
+/// enum GenericParam {
+/// Type(TypeParam),
+/// Lifetime(LifetimeDef),
+/// Const(ConstParam),
+/// }
+///
+/// impl Parse for GenericParam {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// let lookahead = input.lookahead1();
+/// if lookahead.peek(Ident) {
+/// input.parse().map(GenericParam::Type)
+/// } else if lookahead.peek(Lifetime) {
+/// input.parse().map(GenericParam::Lifetime)
+/// } else if lookahead.peek(Token![const]) {
+/// input.parse().map(GenericParam::Const)
+/// } else {
+/// Err(lookahead.error())
+/// }
+/// }
+/// }
+/// ```
+pub struct Lookahead1<'a> {
+ scope: Span,
+ cursor: Cursor<'a>,
+ comparisons: RefCell<Vec<&'static str>>,
+}
+
+pub fn new(scope: Span, cursor: Cursor) -> Lookahead1 {
+ Lookahead1 {
+ scope,
+ cursor,
+ comparisons: RefCell::new(Vec::new()),
+ }
+}
+
+fn peek_impl(
+ lookahead: &Lookahead1,
+ peek: fn(Cursor) -> bool,
+ display: fn() -> &'static str,
+) -> bool {
+ if peek(lookahead.cursor) {
+ return true;
+ }
+ lookahead.comparisons.borrow_mut().push(display());
+ false
+}
+
+impl<'a> Lookahead1<'a> {
+ /// Looks at the next token in the parse stream to determine whether it
+ /// matches the requested type of token.
+ ///
+ /// # Syntax
+ ///
+ /// Note that this method does not use turbofish syntax. Pass the peek type
+ /// inside of parentheses.
+ ///
+ /// - `input.peek(Token![struct])`
+ /// - `input.peek(Token![==])`
+ /// - `input.peek(Ident)`&emsp;*(does not accept keywords)*
+ /// - `input.peek(Ident::peek_any)`
+ /// - `input.peek(Lifetime)`
+ /// - `input.peek(token::Brace)`
+ pub fn peek<T: Peek>(&self, token: T) -> bool {
+ let _ = token;
+ peek_impl(self, T::Token::peek, T::Token::display)
+ }
+
+ /// Triggers an error at the current position of the parse stream.
+ ///
+ /// The error message will identify all of the expected token types that
+ /// have been peeked against this lookahead instance.
+ pub fn error(self) -> Error {
+ let comparisons = self.comparisons.borrow();
+ match comparisons.len() {
+ 0 => {
+ if self.cursor.eof() {
+ Error::new(self.scope, "unexpected end of input")
+ } else {
+ Error::new(self.cursor.span(), "unexpected token")
+ }
+ }
+ 1 => {
+ let message = format!("expected {}", comparisons[0]);
+ error::new_at(self.scope, self.cursor, message)
+ }
+ 2 => {
+ let message = format!("expected {} or {}", comparisons[0], comparisons[1]);
+ error::new_at(self.scope, self.cursor, message)
+ }
+ _ => {
+ let join = comparisons.join(", ");
+ let message = format!("expected one of: {}", join);
+ error::new_at(self.scope, self.cursor, message)
+ }
+ }
+ }
+}
+
+/// Types that can be parsed by looking at just one token.
+///
+/// Use [`ParseStream::peek`] to peek one of these types in a parse stream
+/// without consuming it from the stream.
+///
+/// This trait is sealed and cannot be implemented for types outside of Syn.
+///
+/// [`ParseStream::peek`]: crate::parse::ParseBuffer::peek
+pub trait Peek: Sealed {
+ // Not public API.
+ #[doc(hidden)]
+ type Token: Token;
+}
+
+impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Peek for F {
+ type Token = T;
+}
+
+pub enum TokenMarker {}
+
+impl<S> IntoSpans<S> for TokenMarker {
+ fn into_spans(self) -> S {
+ match self {}
+ }
+}
+
+pub fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool {
+ cursor.group(delimiter).is_some()
+}
+
+impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Sealed for F {}
diff --git a/syn/src/mac.rs b/syn/src/mac.rs
new file mode 100644
index 0000000..6c3dcae
--- /dev/null
+++ b/syn/src/mac.rs
@@ -0,0 +1,239 @@
+use super::*;
+use crate::token::{Brace, Bracket, Paren};
+use proc_macro2::TokenStream;
+#[cfg(feature = "parsing")]
+use proc_macro2::{Delimiter, Span, TokenTree};
+
+#[cfg(feature = "parsing")]
+use crate::parse::{Parse, ParseStream, Parser, Result};
+#[cfg(feature = "extra-traits")]
+use crate::tt::TokenStreamHelper;
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+
+ast_struct! {
+ /// A macro invocation: `println!("{}", mac)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Macro #manual_extra_traits {
+ pub path: Path,
+ pub bang_token: Token![!],
+ pub delimiter: MacroDelimiter,
+ pub tokens: TokenStream,
+ }
+}
+
+ast_enum! {
+ /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum MacroDelimiter {
+ Paren(Paren),
+ Brace(Brace),
+ Bracket(Bracket),
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Macro {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Macro {
+ fn eq(&self, other: &Self) -> bool {
+ self.path == other.path
+ && self.bang_token == other.bang_token
+ && self.delimiter == other.delimiter
+ && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Macro {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.path.hash(state);
+ self.bang_token.hash(state);
+ self.delimiter.hash(state);
+ TokenStreamHelper(&self.tokens).hash(state);
+ }
+}
+
+#[cfg(feature = "parsing")]
+fn delimiter_span(delimiter: &MacroDelimiter) -> Span {
+ match delimiter {
+ MacroDelimiter::Paren(token) => token.span,
+ MacroDelimiter::Brace(token) => token.span,
+ MacroDelimiter::Bracket(token) => token.span,
+ }
+}
+
+impl Macro {
+ /// Parse the tokens within the macro invocation's delimiters into a syntax
+ /// tree.
+ ///
+ /// This is equivalent to `syn::parse2::<T>(mac.tokens)` except that it
+ /// produces a more useful span when `tokens` is empty.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{parse_quote, Expr, ExprLit, Ident, Lit, LitStr, Macro, Token};
+ /// use syn::ext::IdentExt;
+ /// use syn::parse::{Error, Parse, ParseStream, Result};
+ /// use syn::punctuated::Punctuated;
+ ///
+ /// // The arguments expected by libcore's format_args macro, and as a
+ /// // result most other formatting and printing macros like println.
+ /// //
+ /// // println!("{} is {number:.prec$}", "x", prec=5, number=0.01)
+ /// struct FormatArgs {
+ /// format_string: Expr,
+ /// positional_args: Vec<Expr>,
+ /// named_args: Vec<(Ident, Expr)>,
+ /// }
+ ///
+ /// impl Parse for FormatArgs {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// let format_string: Expr;
+ /// let mut positional_args = Vec::new();
+ /// let mut named_args = Vec::new();
+ ///
+ /// format_string = input.parse()?;
+ /// while !input.is_empty() {
+ /// input.parse::<Token![,]>()?;
+ /// if input.is_empty() {
+ /// break;
+ /// }
+ /// if input.peek(Ident::peek_any) && input.peek2(Token![=]) {
+ /// while !input.is_empty() {
+ /// let name: Ident = input.call(Ident::parse_any)?;
+ /// input.parse::<Token![=]>()?;
+ /// let value: Expr = input.parse()?;
+ /// named_args.push((name, value));
+ /// if input.is_empty() {
+ /// break;
+ /// }
+ /// input.parse::<Token![,]>()?;
+ /// }
+ /// break;
+ /// }
+ /// positional_args.push(input.parse()?);
+ /// }
+ ///
+ /// Ok(FormatArgs {
+ /// format_string,
+ /// positional_args,
+ /// named_args,
+ /// })
+ /// }
+ /// }
+ ///
+ /// // Extract the first argument, the format string literal, from an
+ /// // invocation of a formatting or printing macro.
+ /// fn get_format_string(m: &Macro) -> Result<LitStr> {
+ /// let args: FormatArgs = m.parse_body()?;
+ /// match args.format_string {
+ /// Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) => Ok(lit),
+ /// other => {
+ /// // First argument was not a string literal expression.
+ /// // Maybe something like: println!(concat!(...), ...)
+ /// Err(Error::new_spanned(other, "format string must be a string literal"))
+ /// }
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let invocation = parse_quote! {
+ /// println!("{:?}", Instant::now())
+ /// };
+ /// let lit = get_format_string(&invocation).unwrap();
+ /// assert_eq!(lit.value(), "{:?}");
+ /// }
+ /// ```
+ #[cfg(feature = "parsing")]
+ pub fn parse_body<T: Parse>(&self) -> Result<T> {
+ self.parse_body_with(T::parse)
+ }
+
+ /// Parse the tokens within the macro invocation's delimiters using the
+ /// given parser.
+ #[cfg(feature = "parsing")]
+ pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
+ // TODO: see if we can get a group.span_close() span in here as the
+ // scope, rather than the span of the whole group.
+ let scope = delimiter_span(&self.delimiter);
+ crate::parse::parse_scoped(parser, scope, self.tokens.clone())
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
+ input.step(|cursor| {
+ if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
+ let span = g.span();
+ let delimiter = match g.delimiter() {
+ Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
+ Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
+ Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
+ Delimiter::None => {
+ return Err(cursor.error("expected delimiter"));
+ }
+ };
+ Ok(((delimiter, g.stream()), rest))
+ } else {
+ Err(cursor.error("expected delimiter"))
+ }
+ })
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::parse::{Parse, ParseStream, Result};
+
+ impl Parse for Macro {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let tokens;
+ Ok(Macro {
+ path: input.call(Path::parse_mod_style)?,
+ bang_token: input.parse()?,
+ delimiter: {
+ let (delimiter, content) = parse_delimiter(input)?;
+ tokens = content;
+ delimiter
+ },
+ tokens,
+ })
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for Macro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens);
+ self.bang_token.to_tokens(tokens);
+ match &self.delimiter {
+ MacroDelimiter::Paren(paren) => {
+ paren.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
+ }
+ MacroDelimiter::Brace(brace) => {
+ brace.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
+ }
+ MacroDelimiter::Bracket(bracket) => {
+ bracket.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
+ }
+ }
+ }
+ }
+}
diff --git a/syn/src/macros.rs b/syn/src/macros.rs
new file mode 100644
index 0000000..57091c0
--- /dev/null
+++ b/syn/src/macros.rs
@@ -0,0 +1,191 @@
+macro_rules! ast_struct {
+ (
+ [$($attrs_pub:tt)*]
+ struct $name:ident #full $($rest:tt)*
+ ) => {
+ #[cfg(feature = "full")]
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* struct $name $($rest)*
+
+ #[cfg(not(feature = "full"))]
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* struct $name {
+ _noconstruct: (),
+ }
+
+ #[cfg(all(not(feature = "full"), feature = "printing"))]
+ impl ::quote::ToTokens for $name {
+ fn to_tokens(&self, _: &mut ::proc_macro2::TokenStream) {
+ unreachable!()
+ }
+ }
+ };
+
+ (
+ [$($attrs_pub:tt)*]
+ struct $name:ident #manual_extra_traits $($rest:tt)*
+ ) => {
+ #[cfg_attr(feature = "extra-traits", derive(Debug))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* struct $name $($rest)*
+ };
+
+ (
+ [$($attrs_pub:tt)*]
+ struct $name:ident #manual_extra_traits_debug $($rest:tt)*
+ ) => {
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* struct $name $($rest)*
+ };
+
+ (
+ [$($attrs_pub:tt)*]
+ struct $name:ident $($rest:tt)*
+ ) => {
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* struct $name $($rest)*
+ };
+
+ ($($t:tt)*) => {
+ strip_attrs_pub!(ast_struct!($($t)*));
+ };
+}
+
+macro_rules! ast_enum {
+ // Drop the `#no_visit` attribute, if present.
+ (
+ [$($attrs_pub:tt)*]
+ enum $name:ident #no_visit $($rest:tt)*
+ ) => (
+ ast_enum!([$($attrs_pub)*] enum $name $($rest)*);
+ );
+
+ (
+ [$($attrs_pub:tt)*]
+ enum $name:ident #manual_extra_traits $($rest:tt)*
+ ) => (
+ #[cfg_attr(feature = "extra-traits", derive(Debug))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* enum $name $($rest)*
+ );
+
+ (
+ [$($attrs_pub:tt)*]
+ enum $name:ident $($rest:tt)*
+ ) => (
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ $($attrs_pub)* enum $name $($rest)*
+ );
+
+ ($($t:tt)*) => {
+ strip_attrs_pub!(ast_enum!($($t)*));
+ };
+}
+
+macro_rules! ast_enum_of_structs {
+ (
+ $(#[$enum_attr:meta])*
+ $pub:ident $enum:ident $name:ident #$tag:ident $body:tt
+ $($remaining:tt)*
+ ) => {
+ ast_enum!($(#[$enum_attr])* $pub $enum $name #$tag $body);
+ ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
+ };
+
+ (
+ $(#[$enum_attr:meta])*
+ $pub:ident $enum:ident $name:ident $body:tt
+ $($remaining:tt)*
+ ) => {
+ ast_enum!($(#[$enum_attr])* $pub $enum $name $body);
+ ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
+ };
+}
+
+macro_rules! ast_enum_of_structs_impl {
+ (
+ $pub:ident $enum:ident $name:ident {
+ $(
+ $(#[$variant_attr:meta])*
+ $variant:ident $( ($member:ident) )*,
+ )*
+ }
+
+ $($remaining:tt)*
+ ) => {
+ check_keyword_matches!(pub $pub);
+ check_keyword_matches!(enum $enum);
+
+ $($(
+ ast_enum_from_struct!($name::$variant, $member);
+ )*)*
+
+ #[cfg(feature = "printing")]
+ generate_to_tokens! {
+ $($remaining)*
+ ()
+ tokens
+ $name { $($variant $($member)*,)* }
+ }
+ };
+}
+
+macro_rules! ast_enum_from_struct {
+ // No From<TokenStream> for verbatim variants.
+ ($name:ident::Verbatim, $member:ident) => {};
+
+ ($name:ident::$variant:ident, $member:ident) => {
+ impl From<$member> for $name {
+ fn from(e: $member) -> $name {
+ $name::$variant(e)
+ }
+ }
+ };
+}
+
+#[cfg(feature = "printing")]
+macro_rules! generate_to_tokens {
+ (do_not_generate_to_tokens $($foo:tt)*) => ();
+
+ (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident, $($next:tt)*}) => {
+ generate_to_tokens!(
+ ($($arms)* $name::$variant => {})
+ $tokens $name { $($next)* }
+ );
+ };
+
+ (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident $member:ident, $($next:tt)*}) => {
+ generate_to_tokens!(
+ ($($arms)* $name::$variant(_e) => _e.to_tokens($tokens),)
+ $tokens $name { $($next)* }
+ );
+ };
+
+ (($($arms:tt)*) $tokens:ident $name:ident {}) => {
+ impl ::quote::ToTokens for $name {
+ fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) {
+ match self {
+ $($arms)*
+ }
+ }
+ }
+ };
+}
+
+macro_rules! strip_attrs_pub {
+ ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
+ check_keyword_matches!(pub $pub);
+
+ $mac!([$(#[$m])* $pub] $($t)*);
+ };
+}
+
+macro_rules! check_keyword_matches {
+ (struct struct) => {};
+ (enum enum) => {};
+ (pub pub) => {};
+}
diff --git a/syn/src/op.rs b/syn/src/op.rs
new file mode 100644
index 0000000..49fb853
--- /dev/null
+++ b/syn/src/op.rs
@@ -0,0 +1,231 @@
+ast_enum! {
+ /// A binary operator: `+`, `+=`, `&`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum BinOp {
+ /// The `+` operator (addition)
+ Add(Token![+]),
+ /// The `-` operator (subtraction)
+ Sub(Token![-]),
+ /// The `*` operator (multiplication)
+ Mul(Token![*]),
+ /// The `/` operator (division)
+ Div(Token![/]),
+ /// The `%` operator (modulus)
+ Rem(Token![%]),
+ /// The `&&` operator (logical and)
+ And(Token![&&]),
+ /// The `||` operator (logical or)
+ Or(Token![||]),
+ /// The `^` operator (bitwise xor)
+ BitXor(Token![^]),
+ /// The `&` operator (bitwise and)
+ BitAnd(Token![&]),
+ /// The `|` operator (bitwise or)
+ BitOr(Token![|]),
+ /// The `<<` operator (shift left)
+ Shl(Token![<<]),
+ /// The `>>` operator (shift right)
+ Shr(Token![>>]),
+ /// The `==` operator (equality)
+ Eq(Token![==]),
+ /// The `<` operator (less than)
+ Lt(Token![<]),
+ /// The `<=` operator (less than or equal to)
+ Le(Token![<=]),
+ /// The `!=` operator (not equal to)
+ Ne(Token![!=]),
+ /// The `>=` operator (greater than or equal to)
+ Ge(Token![>=]),
+ /// The `>` operator (greater than)
+ Gt(Token![>]),
+ /// The `+=` operator
+ AddEq(Token![+=]),
+ /// The `-=` operator
+ SubEq(Token![-=]),
+ /// The `*=` operator
+ MulEq(Token![*=]),
+ /// The `/=` operator
+ DivEq(Token![/=]),
+ /// The `%=` operator
+ RemEq(Token![%=]),
+ /// The `^=` operator
+ BitXorEq(Token![^=]),
+ /// The `&=` operator
+ BitAndEq(Token![&=]),
+ /// The `|=` operator
+ BitOrEq(Token![|=]),
+ /// The `<<=` operator
+ ShlEq(Token![<<=]),
+ /// The `>>=` operator
+ ShrEq(Token![>>=]),
+ }
+}
+
+ast_enum! {
+ /// A unary operator: `*`, `!`, `-`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum UnOp {
+ /// The `*` operator for dereferencing
+ Deref(Token![*]),
+ /// The `!` operator for logical inversion
+ Not(Token![!]),
+ /// The `-` operator for negation
+ Neg(Token![-]),
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::parse::{Parse, ParseStream, Result};
+
+ fn parse_binop(input: ParseStream) -> Result<BinOp> {
+ if input.peek(Token![&&]) {
+ input.parse().map(BinOp::And)
+ } else if input.peek(Token![||]) {
+ input.parse().map(BinOp::Or)
+ } else if input.peek(Token![<<]) {
+ input.parse().map(BinOp::Shl)
+ } else if input.peek(Token![>>]) {
+ input.parse().map(BinOp::Shr)
+ } else if input.peek(Token![==]) {
+ input.parse().map(BinOp::Eq)
+ } else if input.peek(Token![<=]) {
+ input.parse().map(BinOp::Le)
+ } else if input.peek(Token![!=]) {
+ input.parse().map(BinOp::Ne)
+ } else if input.peek(Token![>=]) {
+ input.parse().map(BinOp::Ge)
+ } else if input.peek(Token![+]) {
+ input.parse().map(BinOp::Add)
+ } else if input.peek(Token![-]) {
+ input.parse().map(BinOp::Sub)
+ } else if input.peek(Token![*]) {
+ input.parse().map(BinOp::Mul)
+ } else if input.peek(Token![/]) {
+ input.parse().map(BinOp::Div)
+ } else if input.peek(Token![%]) {
+ input.parse().map(BinOp::Rem)
+ } else if input.peek(Token![^]) {
+ input.parse().map(BinOp::BitXor)
+ } else if input.peek(Token![&]) {
+ input.parse().map(BinOp::BitAnd)
+ } else if input.peek(Token![|]) {
+ input.parse().map(BinOp::BitOr)
+ } else if input.peek(Token![<]) {
+ input.parse().map(BinOp::Lt)
+ } else if input.peek(Token![>]) {
+ input.parse().map(BinOp::Gt)
+ } else {
+ Err(input.error("expected binary operator"))
+ }
+ }
+
+ impl Parse for BinOp {
+ #[cfg(not(feature = "full"))]
+ fn parse(input: ParseStream) -> Result<Self> {
+ parse_binop(input)
+ }
+
+ #[cfg(feature = "full")]
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Token![+=]) {
+ input.parse().map(BinOp::AddEq)
+ } else if input.peek(Token![-=]) {
+ input.parse().map(BinOp::SubEq)
+ } else if input.peek(Token![*=]) {
+ input.parse().map(BinOp::MulEq)
+ } else if input.peek(Token![/=]) {
+ input.parse().map(BinOp::DivEq)
+ } else if input.peek(Token![%=]) {
+ input.parse().map(BinOp::RemEq)
+ } else if input.peek(Token![^=]) {
+ input.parse().map(BinOp::BitXorEq)
+ } else if input.peek(Token![&=]) {
+ input.parse().map(BinOp::BitAndEq)
+ } else if input.peek(Token![|=]) {
+ input.parse().map(BinOp::BitOrEq)
+ } else if input.peek(Token![<<=]) {
+ input.parse().map(BinOp::ShlEq)
+ } else if input.peek(Token![>>=]) {
+ input.parse().map(BinOp::ShrEq)
+ } else {
+ parse_binop(input)
+ }
+ }
+ }
+
+ impl Parse for UnOp {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![*]) {
+ input.parse().map(UnOp::Deref)
+ } else if lookahead.peek(Token![!]) {
+ input.parse().map(UnOp::Not)
+ } else if lookahead.peek(Token![-]) {
+ input.parse().map(UnOp::Neg)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for BinOp {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ BinOp::Add(t) => t.to_tokens(tokens),
+ BinOp::Sub(t) => t.to_tokens(tokens),
+ BinOp::Mul(t) => t.to_tokens(tokens),
+ BinOp::Div(t) => t.to_tokens(tokens),
+ BinOp::Rem(t) => t.to_tokens(tokens),
+ BinOp::And(t) => t.to_tokens(tokens),
+ BinOp::Or(t) => t.to_tokens(tokens),
+ BinOp::BitXor(t) => t.to_tokens(tokens),
+ BinOp::BitAnd(t) => t.to_tokens(tokens),
+ BinOp::BitOr(t) => t.to_tokens(tokens),
+ BinOp::Shl(t) => t.to_tokens(tokens),
+ BinOp::Shr(t) => t.to_tokens(tokens),
+ BinOp::Eq(t) => t.to_tokens(tokens),
+ BinOp::Lt(t) => t.to_tokens(tokens),
+ BinOp::Le(t) => t.to_tokens(tokens),
+ BinOp::Ne(t) => t.to_tokens(tokens),
+ BinOp::Ge(t) => t.to_tokens(tokens),
+ BinOp::Gt(t) => t.to_tokens(tokens),
+ BinOp::AddEq(t) => t.to_tokens(tokens),
+ BinOp::SubEq(t) => t.to_tokens(tokens),
+ BinOp::MulEq(t) => t.to_tokens(tokens),
+ BinOp::DivEq(t) => t.to_tokens(tokens),
+ BinOp::RemEq(t) => t.to_tokens(tokens),
+ BinOp::BitXorEq(t) => t.to_tokens(tokens),
+ BinOp::BitAndEq(t) => t.to_tokens(tokens),
+ BinOp::BitOrEq(t) => t.to_tokens(tokens),
+ BinOp::ShlEq(t) => t.to_tokens(tokens),
+ BinOp::ShrEq(t) => t.to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for UnOp {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ UnOp::Deref(t) => t.to_tokens(tokens),
+ UnOp::Not(t) => t.to_tokens(tokens),
+ UnOp::Neg(t) => t.to_tokens(tokens),
+ }
+ }
+ }
+}
diff --git a/syn/src/parse.rs b/syn/src/parse.rs
new file mode 100644
index 0000000..96eecce
--- /dev/null
+++ b/syn/src/parse.rs
@@ -0,0 +1,1222 @@
+//! Parsing interface for parsing a token stream into a syntax tree node.
+//!
+//! Parsing in Syn is built on parser functions that take in a [`ParseStream`]
+//! and produce a [`Result<T>`] where `T` is some syntax tree node. Underlying
+//! these parser functions is a lower level mechanism built around the
+//! [`Cursor`] type. `Cursor` is a cheaply copyable cursor over a range of
+//! tokens in a token stream.
+//!
+//! [`ParseStream`]: type.ParseStream.html
+//! [`Result<T>`]: type.Result.html
+//! [`Cursor`]: ../buffer/index.html
+//!
+//! # Example
+//!
+//! Here is a snippet of parsing code to get a feel for the style of the
+//! library. We define data structures for a subset of Rust syntax including
+//! enums (not shown) and structs, then provide implementations of the [`Parse`]
+//! trait to parse these syntax tree data structures from a token stream.
+//!
+//! Once `Parse` impls have been defined, they can be called conveniently from a
+//! procedural macro through [`parse_macro_input!`] as shown at the bottom of
+//! the snippet. If the caller provides syntactically invalid input to the
+//! procedural macro, they will receive a helpful compiler error message
+//! pointing out the exact token that triggered the failure to parse.
+//!
+//! [`parse_macro_input!`]: ../macro.parse_macro_input.html
+//!
+//! ```
+//! extern crate proc_macro;
+//!
+//! use proc_macro::TokenStream;
+//! use syn::{braced, parse_macro_input, token, Field, Ident, Result, Token};
+//! use syn::parse::{Parse, ParseStream};
+//! use syn::punctuated::Punctuated;
+//!
+//! enum Item {
+//! Struct(ItemStruct),
+//! Enum(ItemEnum),
+//! }
+//!
+//! struct ItemStruct {
+//! struct_token: Token![struct],
+//! ident: Ident,
+//! brace_token: token::Brace,
+//! fields: Punctuated<Field, Token![,]>,
+//! }
+//! #
+//! # enum ItemEnum {}
+//!
+//! impl Parse for Item {
+//! fn parse(input: ParseStream) -> Result<Self> {
+//! let lookahead = input.lookahead1();
+//! if lookahead.peek(Token![struct]) {
+//! input.parse().map(Item::Struct)
+//! } else if lookahead.peek(Token![enum]) {
+//! input.parse().map(Item::Enum)
+//! } else {
+//! Err(lookahead.error())
+//! }
+//! }
+//! }
+//!
+//! impl Parse for ItemStruct {
+//! fn parse(input: ParseStream) -> Result<Self> {
+//! let content;
+//! Ok(ItemStruct {
+//! struct_token: input.parse()?,
+//! ident: input.parse()?,
+//! brace_token: braced!(content in input),
+//! fields: content.parse_terminated(Field::parse_named)?,
+//! })
+//! }
+//! }
+//! #
+//! # impl Parse for ItemEnum {
+//! # fn parse(input: ParseStream) -> Result<Self> {
+//! # unimplemented!()
+//! # }
+//! # }
+//!
+//! # const IGNORE: &str = stringify! {
+//! #[proc_macro]
+//! # };
+//! pub fn my_macro(tokens: TokenStream) -> TokenStream {
+//! let input = parse_macro_input!(tokens as Item);
+//!
+//! /* ... */
+//! # "".parse().unwrap()
+//! }
+//! ```
+//!
+//! # The `syn::parse*` functions
+//!
+//! The [`syn::parse`], [`syn::parse2`], and [`syn::parse_str`] functions serve
+//! as an entry point for parsing syntax tree nodes that can be parsed in an
+//! obvious default way. These functions can return any syntax tree node that
+//! implements the [`Parse`] trait, which includes most types in Syn.
+//!
+//! [`syn::parse`]: ../fn.parse.html
+//! [`syn::parse2`]: ../fn.parse2.html
+//! [`syn::parse_str`]: ../fn.parse_str.html
+//! [`Parse`]: trait.Parse.html
+//!
+//! ```
+//! use syn::Type;
+//!
+//! # fn run_parser() -> syn::Result<()> {
+//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?;
+//! # Ok(())
+//! # }
+//! #
+//! # run_parser().unwrap();
+//! ```
+//!
+//! The [`parse_quote!`] macro also uses this approach.
+//!
+//! [`parse_quote!`]: ../macro.parse_quote.html
+//!
+//! # The `Parser` trait
+//!
+//! Some types can be parsed in several ways depending on context. For example
+//! an [`Attribute`] can be either "outer" like `#[...]` or "inner" like
+//! `#![...]` and parsing the wrong one would be a bug. Similarly [`Punctuated`]
+//! may or may not allow trailing punctuation, and parsing it the wrong way
+//! would either reject valid input or accept invalid input.
+//!
+//! [`Attribute`]: ../struct.Attribute.html
+//! [`Punctuated`]: ../punctuated/index.html
+//!
+//! The `Parse` trait is not implemented in these cases because there is no good
+//! behavior to consider the default.
+//!
+//! ```compile_fail
+//! # extern crate proc_macro;
+//! #
+//! # use syn::punctuated::Punctuated;
+//! # use syn::{PathSegment, Result, Token};
+//! #
+//! # fn f(tokens: proc_macro::TokenStream) -> Result<()> {
+//! #
+//! // Can't parse `Punctuated` without knowing whether trailing punctuation
+//! // should be allowed in this context.
+//! let path: Punctuated<PathSegment, Token![::]> = syn::parse(tokens)?;
+//! #
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! In these cases the types provide a choice of parser functions rather than a
+//! single `Parse` implementation, and those parser functions can be invoked
+//! through the [`Parser`] trait.
+//!
+//! [`Parser`]: trait.Parser.html
+//!
+//! ```
+//! extern crate proc_macro;
+//!
+//! use proc_macro::TokenStream;
+//! use syn::parse::Parser;
+//! use syn::punctuated::Punctuated;
+//! use syn::{Attribute, Expr, PathSegment, Result, Token};
+//!
+//! fn call_some_parser_methods(input: TokenStream) -> Result<()> {
+//! // Parse a nonempty sequence of path segments separated by `::` punctuation
+//! // with no trailing punctuation.
+//! let tokens = input.clone();
+//! let parser = Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty;
+//! let _path = parser.parse(tokens)?;
+//!
+//! // Parse a possibly empty sequence of expressions terminated by commas with
+//! // an optional trailing punctuation.
+//! let tokens = input.clone();
+//! let parser = Punctuated::<Expr, Token![,]>::parse_terminated;
+//! let _args = parser.parse(tokens)?;
+//!
+//! // Parse zero or more outer attributes but not inner attributes.
+//! let tokens = input.clone();
+//! let parser = Attribute::parse_outer;
+//! let _attrs = parser.parse(tokens)?;
+//!
+//! Ok(())
+//! }
+//! ```
+//!
+//! ---
+//!
+//! *This module is available if Syn is built with the `"parsing"` feature.*
+
+#[path = "discouraged.rs"]
+pub mod discouraged;
+
+use std::cell::Cell;
+use std::fmt::{self, Debug, Display};
+use std::marker::PhantomData;
+use std::mem;
+use std::ops::Deref;
+use std::rc::Rc;
+use std::str::FromStr;
+
+#[cfg(all(
+ not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
+ feature = "proc-macro"
+))]
+use crate::proc_macro;
+use proc_macro2::{self, Delimiter, Group, Literal, Punct, Span, TokenStream, TokenTree};
+
+use crate::buffer::{Cursor, TokenBuffer};
+use crate::error;
+use crate::lookahead;
+use crate::punctuated::Punctuated;
+use crate::token::Token;
+
+pub use crate::error::{Error, Result};
+pub use crate::lookahead::{Lookahead1, Peek};
+
+/// Parsing interface implemented by all types that can be parsed in a default
+/// way from a token stream.
+pub trait Parse: Sized {
+ fn parse(input: ParseStream) -> Result<Self>;
+}
+
+/// Input to a Syn parser function.
+///
+/// See the methods of this type under the documentation of [`ParseBuffer`]. For
+/// an overview of parsing in Syn, refer to the [module documentation].
+///
+/// [module documentation]: self
+pub type ParseStream<'a> = &'a ParseBuffer<'a>;
+
+/// Cursor position within a buffered token stream.
+///
+/// This type is more commonly used through the type alias [`ParseStream`] which
+/// is an alias for `&ParseBuffer`.
+///
+/// `ParseStream` is the input type for all parser functions in Syn. They have
+/// the signature `fn(ParseStream) -> Result<T>`.
+///
+/// ## Calling a parser function
+///
+/// There is no public way to construct a `ParseBuffer`. Instead, if you are
+/// looking to invoke a parser function that requires `ParseStream` as input,
+/// you will need to go through one of the public parsing entry points.
+///
+/// - The [`parse_macro_input!`] macro if parsing input of a procedural macro;
+/// - One of [the `syn::parse*` functions][syn-parse]; or
+/// - A method of the [`Parser`] trait.
+///
+/// [syn-parse]: index.html#the-synparse-functions
+pub struct ParseBuffer<'a> {
+ scope: Span,
+ // Instead of Cell<Cursor<'a>> so that ParseBuffer<'a> is covariant in 'a.
+ // The rest of the code in this module needs to be careful that only a
+ // cursor derived from this `cell` is ever assigned to this `cell`.
+ //
+ // Cell<Cursor<'a>> cannot be covariant in 'a because then we could take a
+ // ParseBuffer<'a>, upcast to ParseBuffer<'short> for some lifetime shorter
+ // than 'a, and then assign a Cursor<'short> into the Cell.
+ //
+ // By extension, it would not be safe to expose an API that accepts a
+ // Cursor<'a> and trusts that it lives as long as the cursor currently in
+ // the cell.
+ cell: Cell<Cursor<'static>>,
+ marker: PhantomData<Cursor<'a>>,
+ unexpected: Cell<Option<Rc<Cell<Unexpected>>>>,
+}
+
+impl<'a> Drop for ParseBuffer<'a> {
+ fn drop(&mut self) {
+ if !self.is_empty() {
+ let (inner, old_span) = inner_unexpected(self);
+ if old_span.is_none() {
+ inner.set(Unexpected::Some(self.cursor().span()));
+ }
+ }
+ }
+}
+
+impl<'a> Display for ParseBuffer<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(&self.cursor().token_stream(), f)
+ }
+}
+
+impl<'a> Debug for ParseBuffer<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ Debug::fmt(&self.cursor().token_stream(), f)
+ }
+}
+
+/// Cursor state associated with speculative parsing.
+///
+/// This type is the input of the closure provided to [`ParseStream::step`].
+///
+/// [`ParseStream::step`]: ParseBuffer::step
+///
+/// # Example
+///
+/// ```
+/// use proc_macro2::TokenTree;
+/// use syn::Result;
+/// use syn::parse::ParseStream;
+///
+/// // This function advances the stream past the next occurrence of `@`. If
+/// // no `@` is present in the stream, the stream position is unchanged and
+/// // an error is returned.
+/// fn skip_past_next_at(input: ParseStream) -> Result<()> {
+/// input.step(|cursor| {
+/// let mut rest = *cursor;
+/// while let Some((tt, next)) = rest.token_tree() {
+/// match &tt {
+/// TokenTree::Punct(punct) if punct.as_char() == '@' => {
+/// return Ok(((), next));
+/// }
+/// _ => rest = next,
+/// }
+/// }
+/// Err(cursor.error("no `@` was found after this point"))
+/// })
+/// }
+/// #
+/// # fn remainder_after_skipping_past_next_at(
+/// # input: ParseStream,
+/// # ) -> Result<proc_macro2::TokenStream> {
+/// # skip_past_next_at(input)?;
+/// # input.parse()
+/// # }
+/// #
+/// # use syn::parse::Parser;
+/// # let remainder = remainder_after_skipping_past_next_at
+/// # .parse_str("a @ b c")
+/// # .unwrap();
+/// # assert_eq!(remainder.to_string(), "b c");
+/// ```
+#[derive(Copy, Clone)]
+pub struct StepCursor<'c, 'a> {
+ scope: Span,
+ // This field is covariant in 'c.
+ cursor: Cursor<'c>,
+ // This field is contravariant in 'c. Together these make StepCursor
+ // invariant in 'c. Also covariant in 'a. The user cannot cast 'c to a
+ // different lifetime but can upcast into a StepCursor with a shorter
+ // lifetime 'a.
+ //
+ // As long as we only ever construct a StepCursor for which 'c outlives 'a,
+ // this means if ever a StepCursor<'c, 'a> exists we are guaranteed that 'c
+ // outlives 'a.
+ marker: PhantomData<fn(Cursor<'c>) -> Cursor<'a>>,
+}
+
+impl<'c, 'a> Deref for StepCursor<'c, 'a> {
+ type Target = Cursor<'c>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.cursor
+ }
+}
+
+impl<'c, 'a> StepCursor<'c, 'a> {
+ /// Triggers an error at the current position of the parse stream.
+ ///
+ /// The `ParseStream::step` invocation will return this same error without
+ /// advancing the stream state.
+ pub fn error<T: Display>(self, message: T) -> Error {
+ error::new_at(self.scope, self.cursor, message)
+ }
+}
+
+pub(crate) fn advance_step_cursor<'c, 'a>(proof: StepCursor<'c, 'a>, to: Cursor<'c>) -> Cursor<'a> {
+ // Refer to the comments within the StepCursor definition. We use the
+ // fact that a StepCursor<'c, 'a> exists as proof that 'c outlives 'a.
+ // Cursor is covariant in its lifetime parameter so we can cast a
+ // Cursor<'c> to one with the shorter lifetime Cursor<'a>.
+ let _ = proof;
+ unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(to) }
+}
+
+pub(crate) fn new_parse_buffer(
+ scope: Span,
+ cursor: Cursor,
+ unexpected: Rc<Cell<Unexpected>>,
+) -> ParseBuffer {
+ ParseBuffer {
+ scope,
+ // See comment on `cell` in the struct definition.
+ cell: Cell::new(unsafe { mem::transmute::<Cursor, Cursor<'static>>(cursor) }),
+ marker: PhantomData,
+ unexpected: Cell::new(Some(unexpected)),
+ }
+}
+
+#[derive(Clone)]
+pub(crate) enum Unexpected {
+ None,
+ Some(Span),
+ Chain(Rc<Cell<Unexpected>>),
+}
+
+impl Default for Unexpected {
+ fn default() -> Self {
+ Unexpected::None
+ }
+}
+
+// We call this on Cell<Unexpected> and Cell<Option<T>> where temporarily
+// swapping in a None is cheap.
+fn cell_clone<T: Default + Clone>(cell: &Cell<T>) -> T {
+ let prev = cell.take();
+ let ret = prev.clone();
+ cell.set(prev);
+ ret
+}
+
+fn inner_unexpected(buffer: &ParseBuffer) -> (Rc<Cell<Unexpected>>, Option<Span>) {
+ let mut unexpected = get_unexpected(buffer);
+ loop {
+ match cell_clone(&unexpected) {
+ Unexpected::None => return (unexpected, None),
+ Unexpected::Some(span) => return (unexpected, Some(span)),
+ Unexpected::Chain(next) => unexpected = next,
+ }
+ }
+}
+
+pub(crate) fn get_unexpected(buffer: &ParseBuffer) -> Rc<Cell<Unexpected>> {
+ cell_clone(&buffer.unexpected).unwrap()
+}
+
+impl<'a> ParseBuffer<'a> {
+ /// Parses a syntax tree node of type `T`, advancing the position of our
+ /// parse stream past it.
+ pub fn parse<T: Parse>(&self) -> Result<T> {
+ T::parse(self)
+ }
+
+ /// Calls the given parser function to parse a syntax tree node of type `T`
+ /// from this stream.
+ ///
+ /// # Example
+ ///
+ /// The parser below invokes [`Attribute::parse_outer`] to parse a vector of
+ /// zero or more outer attributes.
+ ///
+ /// [`Attribute::parse_outer`]: crate::Attribute::parse_outer
+ ///
+ /// ```
+ /// use syn::{Attribute, Ident, Result, Token};
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// // Parses a unit struct with attributes.
+ /// //
+ /// // #[path = "s.tmpl"]
+ /// // struct S;
+ /// struct UnitStruct {
+ /// attrs: Vec<Attribute>,
+ /// struct_token: Token![struct],
+ /// name: Ident,
+ /// semi_token: Token![;],
+ /// }
+ ///
+ /// impl Parse for UnitStruct {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// Ok(UnitStruct {
+ /// attrs: input.call(Attribute::parse_outer)?,
+ /// struct_token: input.parse()?,
+ /// name: input.parse()?,
+ /// semi_token: input.parse()?,
+ /// })
+ /// }
+ /// }
+ /// ```
+ pub fn call<T>(&self, function: fn(ParseStream) -> Result<T>) -> Result<T> {
+ function(self)
+ }
+
+ /// Looks at the next token in the parse stream to determine whether it
+ /// matches the requested type of token.
+ ///
+ /// Does not advance the position of the parse stream.
+ ///
+ /// # Syntax
+ ///
+ /// Note that this method does not use turbofish syntax. Pass the peek type
+ /// inside of parentheses.
+ ///
+ /// - `input.peek(Token![struct])`
+ /// - `input.peek(Token![==])`
+ /// - `input.peek(Ident)`&emsp;*(does not accept keywords)*
+ /// - `input.peek(Ident::peek_any)`
+ /// - `input.peek(Lifetime)`
+ /// - `input.peek(token::Brace)`
+ ///
+ /// # Example
+ ///
+ /// In this example we finish parsing the list of supertraits when the next
+ /// token in the input is either `where` or an opening curly brace.
+ ///
+ /// ```
+ /// use syn::{braced, token, Generics, Ident, Result, Token, TypeParamBound};
+ /// use syn::parse::{Parse, ParseStream};
+ /// use syn::punctuated::Punctuated;
+ ///
+ /// // Parses a trait definition containing no associated items.
+ /// //
+ /// // trait Marker<'de, T>: A + B<'de> where Box<T>: Clone {}
+ /// struct MarkerTrait {
+ /// trait_token: Token![trait],
+ /// ident: Ident,
+ /// generics: Generics,
+ /// colon_token: Option<Token![:]>,
+ /// supertraits: Punctuated<TypeParamBound, Token![+]>,
+ /// brace_token: token::Brace,
+ /// }
+ ///
+ /// impl Parse for MarkerTrait {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// let trait_token: Token![trait] = input.parse()?;
+ /// let ident: Ident = input.parse()?;
+ /// let mut generics: Generics = input.parse()?;
+ /// let colon_token: Option<Token![:]> = input.parse()?;
+ ///
+ /// let mut supertraits = Punctuated::new();
+ /// if colon_token.is_some() {
+ /// loop {
+ /// supertraits.push_value(input.parse()?);
+ /// if input.peek(Token![where]) || input.peek(token::Brace) {
+ /// break;
+ /// }
+ /// supertraits.push_punct(input.parse()?);
+ /// }
+ /// }
+ ///
+ /// generics.where_clause = input.parse()?;
+ /// let content;
+ /// let empty_brace_token = braced!(content in input);
+ ///
+ /// Ok(MarkerTrait {
+ /// trait_token,
+ /// ident,
+ /// generics,
+ /// colon_token,
+ /// supertraits,
+ /// brace_token: empty_brace_token,
+ /// })
+ /// }
+ /// }
+ /// ```
+ pub fn peek<T: Peek>(&self, token: T) -> bool {
+ let _ = token;
+ T::Token::peek(self.cursor())
+ }
+
+ /// Looks at the second-next token in the parse stream.
+ ///
+ /// This is commonly useful as a way to implement contextual keywords.
+ ///
+ /// # Example
+ ///
+ /// This example needs to use `peek2` because the symbol `union` is not a
+ /// keyword in Rust. We can't use just `peek` and decide to parse a union if
+ /// the very next token is `union`, because someone is free to write a `mod
+ /// union` and a macro invocation that looks like `union::some_macro! { ...
+ /// }`. In other words `union` is a contextual keyword.
+ ///
+ /// ```
+ /// use syn::{Ident, ItemUnion, Macro, Result, Token};
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// // Parses either a union or a macro invocation.
+ /// enum UnionOrMacro {
+ /// // union MaybeUninit<T> { uninit: (), value: T }
+ /// Union(ItemUnion),
+ /// // lazy_static! { ... }
+ /// Macro(Macro),
+ /// }
+ ///
+ /// impl Parse for UnionOrMacro {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// if input.peek(Token![union]) && input.peek2(Ident) {
+ /// input.parse().map(UnionOrMacro::Union)
+ /// } else {
+ /// input.parse().map(UnionOrMacro::Macro)
+ /// }
+ /// }
+ /// }
+ /// ```
+ pub fn peek2<T: Peek>(&self, token: T) -> bool {
+ let _ = token;
+ self.cursor().skip().map_or(false, T::Token::peek)
+ }
+
+ /// Looks at the third-next token in the parse stream.
+ pub fn peek3<T: Peek>(&self, token: T) -> bool {
+ let _ = token;
+ self.cursor()
+ .skip()
+ .and_then(Cursor::skip)
+ .map_or(false, T::Token::peek)
+ }
+
+ /// Parses zero or more occurrences of `T` separated by punctuation of type
+ /// `P`, with optional trailing punctuation.
+ ///
+ /// Parsing continues until the end of this parse stream. The entire content
+ /// of this parse stream must consist of `T` and `P`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use quote::quote;
+ /// #
+ /// use syn::{parenthesized, token, Ident, Result, Token, Type};
+ /// use syn::parse::{Parse, ParseStream};
+ /// use syn::punctuated::Punctuated;
+ ///
+ /// // Parse a simplified tuple struct syntax like:
+ /// //
+ /// // struct S(A, B);
+ /// struct TupleStruct {
+ /// struct_token: Token![struct],
+ /// ident: Ident,
+ /// paren_token: token::Paren,
+ /// fields: Punctuated<Type, Token![,]>,
+ /// semi_token: Token![;],
+ /// }
+ ///
+ /// impl Parse for TupleStruct {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// let content;
+ /// Ok(TupleStruct {
+ /// struct_token: input.parse()?,
+ /// ident: input.parse()?,
+ /// paren_token: parenthesized!(content in input),
+ /// fields: content.parse_terminated(Type::parse)?,
+ /// semi_token: input.parse()?,
+ /// })
+ /// }
+ /// }
+ /// #
+ /// # let input = quote! {
+ /// # struct S(A, B);
+ /// # };
+ /// # syn::parse2::<TupleStruct>(input).unwrap();
+ /// ```
+ pub fn parse_terminated<T, P: Parse>(
+ &self,
+ parser: fn(ParseStream) -> Result<T>,
+ ) -> Result<Punctuated<T, P>> {
+ Punctuated::parse_terminated_with(self, parser)
+ }
+
+ /// Returns whether there are tokens remaining in this stream.
+ ///
+ /// This method returns true at the end of the content of a set of
+ /// delimiters, as well as at the very end of the complete macro input.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{braced, token, Ident, Item, Result, Token};
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// // Parses a Rust `mod m { ... }` containing zero or more items.
+ /// struct Mod {
+ /// mod_token: Token![mod],
+ /// name: Ident,
+ /// brace_token: token::Brace,
+ /// items: Vec<Item>,
+ /// }
+ ///
+ /// impl Parse for Mod {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// let content;
+ /// Ok(Mod {
+ /// mod_token: input.parse()?,
+ /// name: input.parse()?,
+ /// brace_token: braced!(content in input),
+ /// items: {
+ /// let mut items = Vec::new();
+ /// while !content.is_empty() {
+ /// items.push(content.parse()?);
+ /// }
+ /// items
+ /// },
+ /// })
+ /// }
+ /// }
+ /// ```
+ pub fn is_empty(&self) -> bool {
+ self.cursor().eof()
+ }
+
+ /// Constructs a helper for peeking at the next token in this stream and
+ /// building an error message if it is not one of a set of expected tokens.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, Token, TypeParam};
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// // A generic parameter, a single one of the comma-separated elements inside
+ /// // angle brackets in:
+ /// //
+ /// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... }
+ /// //
+ /// // On invalid input, lookahead gives us a reasonable error message.
+ /// //
+ /// // error: expected one of: identifier, lifetime, `const`
+ /// // |
+ /// // 5 | fn f<!Sized>() {}
+ /// // | ^
+ /// enum GenericParam {
+ /// Type(TypeParam),
+ /// Lifetime(LifetimeDef),
+ /// Const(ConstParam),
+ /// }
+ ///
+ /// impl Parse for GenericParam {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// let lookahead = input.lookahead1();
+ /// if lookahead.peek(Ident) {
+ /// input.parse().map(GenericParam::Type)
+ /// } else if lookahead.peek(Lifetime) {
+ /// input.parse().map(GenericParam::Lifetime)
+ /// } else if lookahead.peek(Token![const]) {
+ /// input.parse().map(GenericParam::Const)
+ /// } else {
+ /// Err(lookahead.error())
+ /// }
+ /// }
+ /// }
+ /// ```
+ pub fn lookahead1(&self) -> Lookahead1<'a> {
+ lookahead::new(self.scope, self.cursor())
+ }
+
+ /// Forks a parse stream so that parsing tokens out of either the original
+ /// or the fork does not advance the position of the other.
+ ///
+ /// # Performance
+ ///
+ /// Forking a parse stream is a cheap fixed amount of work and does not
+ /// involve copying token buffers. Where you might hit performance problems
+ /// is if your macro ends up parsing a large amount of content more than
+ /// once.
+ ///
+ /// ```
+ /// # use syn::{Expr, Result};
+ /// # use syn::parse::ParseStream;
+ /// #
+ /// # fn bad(input: ParseStream) -> Result<Expr> {
+ /// // Do not do this.
+ /// if input.fork().parse::<Expr>().is_ok() {
+ /// return input.parse::<Expr>();
+ /// }
+ /// # unimplemented!()
+ /// # }
+ /// ```
+ ///
+ /// As a rule, avoid parsing an unbounded amount of tokens out of a forked
+ /// parse stream. Only use a fork when the amount of work performed against
+ /// the fork is small and bounded.
+ ///
+ /// When complex speculative parsing against the forked stream is
+ /// unavoidable, use [`parse::discouraged::Speculative`] to advance the
+ /// original stream once the fork's parse is determined to have been
+ /// successful.
+ ///
+ /// For a lower level way to perform speculative parsing at the token level,
+ /// consider using [`ParseStream::step`] instead.
+ ///
+ /// [`parse::discouraged::Speculative`]: discouraged::Speculative
+ /// [`ParseStream::step`]: ParseBuffer::step
+ ///
+ /// # Example
+ ///
+ /// The parse implementation shown here parses possibly restricted `pub`
+ /// visibilities.
+ ///
+ /// - `pub`
+ /// - `pub(crate)`
+ /// - `pub(self)`
+ /// - `pub(super)`
+ /// - `pub(in some::path)`
+ ///
+ /// To handle the case of visibilities inside of tuple structs, the parser
+ /// needs to distinguish parentheses that specify visibility restrictions
+ /// from parentheses that form part of a tuple type.
+ ///
+ /// ```
+ /// # struct A;
+ /// # struct B;
+ /// # struct C;
+ /// #
+ /// struct S(pub(crate) A, pub (B, C));
+ /// ```
+ ///
+ /// In this example input the first tuple struct element of `S` has
+ /// `pub(crate)` visibility while the second tuple struct element has `pub`
+ /// visibility; the parentheses around `(B, C)` are part of the type rather
+ /// than part of a visibility restriction.
+ ///
+ /// The parser uses a forked parse stream to check the first token inside of
+ /// parentheses after the `pub` keyword. This is a small bounded amount of
+ /// work performed against the forked parse stream.
+ ///
+ /// ```
+ /// use syn::{parenthesized, token, Ident, Path, Result, Token};
+ /// use syn::ext::IdentExt;
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// struct PubVisibility {
+ /// pub_token: Token![pub],
+ /// restricted: Option<Restricted>,
+ /// }
+ ///
+ /// struct Restricted {
+ /// paren_token: token::Paren,
+ /// in_token: Option<Token![in]>,
+ /// path: Path,
+ /// }
+ ///
+ /// impl Parse for PubVisibility {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// let pub_token: Token![pub] = input.parse()?;
+ ///
+ /// if input.peek(token::Paren) {
+ /// let ahead = input.fork();
+ /// let mut content;
+ /// parenthesized!(content in ahead);
+ ///
+ /// if content.peek(Token![crate])
+ /// || content.peek(Token![self])
+ /// || content.peek(Token![super])
+ /// {
+ /// return Ok(PubVisibility {
+ /// pub_token,
+ /// restricted: Some(Restricted {
+ /// paren_token: parenthesized!(content in input),
+ /// in_token: None,
+ /// path: Path::from(content.call(Ident::parse_any)?),
+ /// }),
+ /// });
+ /// } else if content.peek(Token![in]) {
+ /// return Ok(PubVisibility {
+ /// pub_token,
+ /// restricted: Some(Restricted {
+ /// paren_token: parenthesized!(content in input),
+ /// in_token: Some(content.parse()?),
+ /// path: content.call(Path::parse_mod_style)?,
+ /// }),
+ /// });
+ /// }
+ /// }
+ ///
+ /// Ok(PubVisibility {
+ /// pub_token,
+ /// restricted: None,
+ /// })
+ /// }
+ /// }
+ /// ```
+ pub fn fork(&self) -> Self {
+ ParseBuffer {
+ scope: self.scope,
+ cell: self.cell.clone(),
+ marker: PhantomData,
+ // Not the parent's unexpected. Nothing cares whether the clone
+ // parses all the way unless we `advance_to`.
+ unexpected: Cell::new(Some(Rc::new(Cell::new(Unexpected::None)))),
+ }
+ }
+
+ /// Triggers an error at the current position of the parse stream.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{Expr, Result, Token};
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// // Some kind of loop: `while` or `for` or `loop`.
+ /// struct Loop {
+ /// expr: Expr,
+ /// }
+ ///
+ /// impl Parse for Loop {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// if input.peek(Token![while])
+ /// || input.peek(Token![for])
+ /// || input.peek(Token![loop])
+ /// {
+ /// Ok(Loop {
+ /// expr: input.parse()?,
+ /// })
+ /// } else {
+ /// Err(input.error("expected some kind of loop"))
+ /// }
+ /// }
+ /// }
+ /// ```
+ pub fn error<T: Display>(&self, message: T) -> Error {
+ error::new_at(self.scope, self.cursor(), message)
+ }
+
+ /// Speculatively parses tokens from this parse stream, advancing the
+ /// position of this stream only if parsing succeeds.
+ ///
+ /// This is a powerful low-level API used for defining the `Parse` impls of
+ /// the basic built-in token types. It is not something that will be used
+ /// widely outside of the Syn codebase.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use proc_macro2::TokenTree;
+ /// use syn::Result;
+ /// use syn::parse::ParseStream;
+ ///
+ /// // This function advances the stream past the next occurrence of `@`. If
+ /// // no `@` is present in the stream, the stream position is unchanged and
+ /// // an error is returned.
+ /// fn skip_past_next_at(input: ParseStream) -> Result<()> {
+ /// input.step(|cursor| {
+ /// let mut rest = *cursor;
+ /// while let Some((tt, next)) = rest.token_tree() {
+ /// match &tt {
+ /// TokenTree::Punct(punct) if punct.as_char() == '@' => {
+ /// return Ok(((), next));
+ /// }
+ /// _ => rest = next,
+ /// }
+ /// }
+ /// Err(cursor.error("no `@` was found after this point"))
+ /// })
+ /// }
+ /// #
+ /// # fn remainder_after_skipping_past_next_at(
+ /// # input: ParseStream,
+ /// # ) -> Result<proc_macro2::TokenStream> {
+ /// # skip_past_next_at(input)?;
+ /// # input.parse()
+ /// # }
+ /// #
+ /// # use syn::parse::Parser;
+ /// # let remainder = remainder_after_skipping_past_next_at
+ /// # .parse_str("a @ b c")
+ /// # .unwrap();
+ /// # assert_eq!(remainder.to_string(), "b c");
+ /// ```
+ pub fn step<F, R>(&self, function: F) -> Result<R>
+ where
+ F: for<'c> FnOnce(StepCursor<'c, 'a>) -> Result<(R, Cursor<'c>)>,
+ {
+ // Since the user's function is required to work for any 'c, we know
+ // that the Cursor<'c> they return is either derived from the input
+ // StepCursor<'c, 'a> or from a Cursor<'static>.
+ //
+ // It would not be legal to write this function without the invariant
+ // lifetime 'c in StepCursor<'c, 'a>. If this function were written only
+ // in terms of 'a, the user could take our ParseBuffer<'a>, upcast it to
+ // a ParseBuffer<'short> which some shorter lifetime than 'a, invoke
+ // `step` on their ParseBuffer<'short> with a closure that returns
+ // Cursor<'short>, and we would wrongly write that Cursor<'short> into
+ // the Cell intended to hold Cursor<'a>.
+ //
+ // In some cases it may be necessary for R to contain a Cursor<'a>.
+ // Within Syn we solve this using `advance_step_cursor` which uses the
+ // existence of a StepCursor<'c, 'a> as proof that it is safe to cast
+ // from Cursor<'c> to Cursor<'a>. If needed outside of Syn, it would be
+ // safe to expose that API as a method on StepCursor.
+ let (node, rest) = function(StepCursor {
+ scope: self.scope,
+ cursor: self.cell.get(),
+ marker: PhantomData,
+ })?;
+ self.cell.set(rest);
+ Ok(node)
+ }
+
+ /// Returns the `Span` of the next token in the parse stream, or
+ /// `Span::call_site()` if this parse stream has completely exhausted its
+ /// input `TokenStream`.
+ pub fn span(&self) -> Span {
+ let cursor = self.cursor();
+ if cursor.eof() {
+ self.scope
+ } else {
+ crate::buffer::open_span_of_group(cursor)
+ }
+ }
+
+ /// Provides low-level access to the token representation underlying this
+ /// parse stream.
+ ///
+ /// Cursors are immutable so no operations you perform against the cursor
+ /// will affect the state of this parse stream.
+ pub fn cursor(&self) -> Cursor<'a> {
+ self.cell.get()
+ }
+
+ fn check_unexpected(&self) -> Result<()> {
+ match inner_unexpected(self).1 {
+ Some(span) => Err(Error::new(span, "unexpected token")),
+ None => Ok(()),
+ }
+ }
+}
+
+impl<T: Parse> Parse for Box<T> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.parse().map(Box::new)
+ }
+}
+
+impl<T: Parse + Token> Parse for Option<T> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if T::peek(input.cursor()) {
+ Ok(Some(input.parse()?))
+ } else {
+ Ok(None)
+ }
+ }
+}
+
+impl Parse for TokenStream {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| Ok((cursor.token_stream(), Cursor::empty())))
+ }
+}
+
+impl Parse for TokenTree {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| match cursor.token_tree() {
+ Some((tt, rest)) => Ok((tt, rest)),
+ None => Err(cursor.error("expected token tree")),
+ })
+ }
+}
+
+impl Parse for Group {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| {
+ for delim in &[Delimiter::Parenthesis, Delimiter::Brace, Delimiter::Bracket] {
+ if let Some((inside, span, rest)) = cursor.group(*delim) {
+ let mut group = Group::new(*delim, inside.token_stream());
+ group.set_span(span);
+ return Ok((group, rest));
+ }
+ }
+ Err(cursor.error("expected group token"))
+ })
+ }
+}
+
+impl Parse for Punct {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| match cursor.punct() {
+ Some((punct, rest)) => Ok((punct, rest)),
+ None => Err(cursor.error("expected punctuation token")),
+ })
+ }
+}
+
+impl Parse for Literal {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| match cursor.literal() {
+ Some((literal, rest)) => Ok((literal, rest)),
+ None => Err(cursor.error("expected literal token")),
+ })
+ }
+}
+
+/// Parser that can parse Rust tokens into a particular syntax tree node.
+///
+/// Refer to the [module documentation] for details about parsing in Syn.
+///
+/// [module documentation]: self
+///
+/// *This trait is available if Syn is built with the `"parsing"` feature.*
+pub trait Parser: Sized {
+ type Output;
+
+ /// Parse a proc-macro2 token stream into the chosen syntax tree node.
+ ///
+ /// This function will check that the input is fully parsed. If there are
+ /// any unparsed tokens at the end of the stream, an error is returned.
+ fn parse2(self, tokens: TokenStream) -> Result<Self::Output>;
+
+ /// Parse tokens of source code into the chosen syntax tree node.
+ ///
+ /// This function will check that the input is fully parsed. If there are
+ /// any unparsed tokens at the end of the stream, an error is returned.
+ ///
+ /// *This method is available if Syn is built with both the `"parsing"` and
+ /// `"proc-macro"` features.*
+ #[cfg(all(
+ not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
+ feature = "proc-macro"
+ ))]
+ fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output> {
+ self.parse2(proc_macro2::TokenStream::from(tokens))
+ }
+
+ /// Parse a string of Rust code into the chosen syntax tree node.
+ ///
+ /// This function will check that the input is fully parsed. If there are
+ /// any unparsed tokens at the end of the string, an error is returned.
+ ///
+ /// # Hygiene
+ ///
+ /// Every span in the resulting syntax tree will be set to resolve at the
+ /// macro call site.
+ fn parse_str(self, s: &str) -> Result<Self::Output> {
+ self.parse2(proc_macro2::TokenStream::from_str(s)?)
+ }
+
+ // Not public API.
+ #[doc(hidden)]
+ fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> {
+ let _ = scope;
+ self.parse2(tokens)
+ }
+
+ // Not public API.
+ #[doc(hidden)]
+ fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> {
+ input.parse().and_then(|tokens| self.parse2(tokens))
+ }
+}
+
+fn tokens_to_parse_buffer(tokens: &TokenBuffer) -> ParseBuffer {
+ let scope = Span::call_site();
+ let cursor = tokens.begin();
+ let unexpected = Rc::new(Cell::new(Unexpected::None));
+ new_parse_buffer(scope, cursor, unexpected)
+}
+
+impl<F, T> Parser for F
+where
+ F: FnOnce(ParseStream) -> Result<T>,
+{
+ type Output = T;
+
+ fn parse2(self, tokens: TokenStream) -> Result<T> {
+ let buf = TokenBuffer::new2(tokens);
+ let state = tokens_to_parse_buffer(&buf);
+ let node = self(&state)?;
+ state.check_unexpected()?;
+ if state.is_empty() {
+ Ok(node)
+ } else {
+ Err(state.error("unexpected token"))
+ }
+ }
+
+ #[doc(hidden)]
+ fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> {
+ let buf = TokenBuffer::new2(tokens);
+ let cursor = buf.begin();
+ let unexpected = Rc::new(Cell::new(Unexpected::None));
+ let state = new_parse_buffer(scope, cursor, unexpected);
+ let node = self(&state)?;
+ state.check_unexpected()?;
+ if state.is_empty() {
+ Ok(node)
+ } else {
+ Err(state.error("unexpected token"))
+ }
+ }
+
+ #[doc(hidden)]
+ fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> {
+ self(input)
+ }
+}
+
+pub(crate) fn parse_scoped<F: Parser>(f: F, scope: Span, tokens: TokenStream) -> Result<F::Output> {
+ f.__parse_scoped(scope, tokens)
+}
+
+pub(crate) fn parse_stream<F: Parser>(f: F, input: ParseStream) -> Result<F::Output> {
+ f.__parse_stream(input)
+}
+
+/// An empty syntax tree node that consumes no tokens when parsed.
+///
+/// This is useful for attribute macros that want to ensure they are not
+/// provided any attribute args.
+///
+/// ```
+/// extern crate proc_macro;
+///
+/// use proc_macro::TokenStream;
+/// use syn::parse_macro_input;
+/// use syn::parse::Nothing;
+///
+/// # const IGNORE: &str = stringify! {
+/// #[proc_macro_attribute]
+/// # };
+/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream {
+/// parse_macro_input!(args as Nothing);
+///
+/// /* ... */
+/// # "".parse().unwrap()
+/// }
+/// ```
+///
+/// ```text
+/// error: unexpected token
+/// --> src/main.rs:3:19
+/// |
+/// 3 | #[my_attr(asdf)]
+/// | ^^^^
+/// ```
+pub struct Nothing;
+
+impl Parse for Nothing {
+ fn parse(_input: ParseStream) -> Result<Self> {
+ Ok(Nothing)
+ }
+}
diff --git a/syn/src/parse_macro_input.rs b/syn/src/parse_macro_input.rs
new file mode 100644
index 0000000..d6e0725
--- /dev/null
+++ b/syn/src/parse_macro_input.rs
@@ -0,0 +1,110 @@
+/// Parse the input TokenStream of a macro, triggering a compile error if the
+/// tokens fail to parse.
+///
+/// Refer to the [`parse` module] documentation for more details about parsing
+/// in Syn.
+///
+/// [`parse` module]: crate::rustdoc_workaround::parse_module
+///
+/// <br>
+///
+/// # Intended usage
+///
+/// This macro must be called from a function that returns
+/// `proc_macro::TokenStream`. Usually this will be your proc macro entry point,
+/// the function that has the #\[proc_macro\] / #\[proc_macro_derive\] /
+/// #\[proc_macro_attribute\] attribute.
+///
+/// ```
+/// extern crate proc_macro;
+///
+/// use proc_macro::TokenStream;
+/// use syn::{parse_macro_input, Result};
+/// use syn::parse::{Parse, ParseStream};
+///
+/// struct MyMacroInput {
+/// /* ... */
+/// }
+///
+/// impl Parse for MyMacroInput {
+/// fn parse(input: ParseStream) -> Result<Self> {
+/// /* ... */
+/// # Ok(MyMacroInput {})
+/// }
+/// }
+///
+/// # const IGNORE: &str = stringify! {
+/// #[proc_macro]
+/// # };
+/// pub fn my_macro(tokens: TokenStream) -> TokenStream {
+/// let input = parse_macro_input!(tokens as MyMacroInput);
+///
+/// /* ... */
+/// # "".parse().unwrap()
+/// }
+/// ```
+#[macro_export(local_inner_macros)]
+macro_rules! parse_macro_input {
+ ($tokenstream:ident as $ty:ty) => {
+ match $crate::parse_macro_input::parse::<$ty>($tokenstream) {
+ $crate::export::Ok(data) => data,
+ $crate::export::Err(err) => {
+ return $crate::export::TokenStream::from(err.to_compile_error());
+ }
+ }
+ };
+ ($tokenstream:ident) => {
+ parse_macro_input!($tokenstream as _)
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Can parse any type that implements Parse.
+
+use crate::parse::{Parse, ParseStream, Parser, Result};
+use proc_macro::TokenStream;
+
+// Not public API.
+#[doc(hidden)]
+pub fn parse<T: ParseMacroInput>(token_stream: TokenStream) -> Result<T> {
+ T::parse.parse(token_stream)
+}
+
+// Not public API.
+#[doc(hidden)]
+pub trait ParseMacroInput: Sized {
+ fn parse(input: ParseStream) -> Result<Self>;
+}
+
+impl<T: Parse> ParseMacroInput for T {
+ fn parse(input: ParseStream) -> Result<Self> {
+ <T as Parse>::parse(input)
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Any other types that we want `parse_macro_input!` to be able to parse.
+
+#[cfg(any(feature = "full", feature = "derive"))]
+use crate::AttributeArgs;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+impl ParseMacroInput for AttributeArgs {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut metas = Vec::new();
+
+ loop {
+ if input.is_empty() {
+ break;
+ }
+ let value = input.parse()?;
+ metas.push(value);
+ if input.is_empty() {
+ break;
+ }
+ input.parse::<Token![,]>()?;
+ }
+
+ Ok(metas)
+ }
+}
diff --git a/syn/src/parse_quote.rs b/syn/src/parse_quote.rs
new file mode 100644
index 0000000..18a47b9
--- /dev/null
+++ b/syn/src/parse_quote.rs
@@ -0,0 +1,131 @@
+/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
+/// type inference to figure out a return type for those tokens.
+///
+/// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html
+///
+/// The return type can be any syntax tree node that implements the [`Parse`]
+/// trait.
+///
+/// [`Parse`]: parse::Parse
+///
+/// ```
+/// use quote::quote;
+/// use syn::{parse_quote, Stmt};
+///
+/// fn main() {
+/// let name = quote!(v);
+/// let ty = quote!(u8);
+///
+/// let stmt: Stmt = parse_quote! {
+/// let #name: #ty = Default::default();
+/// };
+///
+/// println!("{:#?}", stmt);
+/// }
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature,
+/// although interpolation of syntax tree nodes into the quoted tokens is only
+/// supported if Syn is built with the `"printing"` feature as well.*
+///
+/// # Example
+///
+/// The following helper function adds a bound `T: HeapSize` to every type
+/// parameter `T` in the input generics.
+///
+/// ```
+/// use syn::{parse_quote, Generics, GenericParam};
+///
+/// // Add a bound `T: HeapSize` to every type parameter T.
+/// fn add_trait_bounds(mut generics: Generics) -> Generics {
+/// for param in &mut generics.params {
+/// if let GenericParam::Type(type_param) = param {
+/// type_param.bounds.push(parse_quote!(HeapSize));
+/// }
+/// }
+/// generics
+/// }
+/// ```
+///
+/// # Special cases
+///
+/// This macro can parse the following additional types as a special case even
+/// though they do not implement the `Parse` trait.
+///
+/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
+/// or inner like `#![...]`
+/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
+/// `P` with optional trailing punctuation
+///
+/// [`Punctuated<T, P>`]: punctuated::Punctuated
+///
+/// # Panics
+///
+/// Panics if the tokens fail to parse as the expected syntax tree type. The
+/// caller is responsible for ensuring that the input tokens are syntactically
+/// valid.
+//
+// TODO: allow Punctuated to be inferred as intra doc link, currently blocked on
+// https://github.com/rust-lang/rust/issues/62834
+#[macro_export(local_inner_macros)]
+macro_rules! parse_quote {
+ ($($tt:tt)*) => {
+ $crate::parse_quote::parse(
+ $crate::export::From::from(
+ $crate::export::quote::quote!($($tt)*)
+ )
+ )
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Can parse any type that implements Parse.
+
+use crate::parse::{Parse, ParseStream, Parser, Result};
+use proc_macro2::TokenStream;
+
+// Not public API.
+#[doc(hidden)]
+pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
+ let parser = T::parse;
+ match parser.parse2(token_stream) {
+ Ok(t) => t,
+ Err(err) => panic!("{}", err),
+ }
+}
+
+// Not public API.
+#[doc(hidden)]
+pub trait ParseQuote: Sized {
+ fn parse(input: ParseStream) -> Result<Self>;
+}
+
+impl<T: Parse> ParseQuote for T {
+ fn parse(input: ParseStream) -> Result<Self> {
+ <T as Parse>::parse(input)
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Any other types that we want `parse_quote!` to be able to parse.
+
+use crate::punctuated::Punctuated;
+#[cfg(any(feature = "full", feature = "derive"))]
+use crate::{attr, Attribute};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+impl ParseQuote for Attribute {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Token![#]) && input.peek2(Token![!]) {
+ attr::parsing::single_parse_inner(input)
+ } else {
+ attr::parsing::single_parse_outer(input)
+ }
+ }
+}
+
+impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse_terminated(input)
+ }
+}
diff --git a/syn/src/pat.rs b/syn/src/pat.rs
new file mode 100644
index 0000000..262129b
--- /dev/null
+++ b/syn/src/pat.rs
@@ -0,0 +1,903 @@
+use super::*;
+use crate::punctuated::Punctuated;
+#[cfg(feature = "extra-traits")]
+use crate::tt::TokenStreamHelper;
+use proc_macro2::TokenStream;
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+
+ast_enum_of_structs! {
+ /// A pattern in a local binding, function signature, match expression, or
+ /// various other places.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum Pat #manual_extra_traits {
+ /// A box pattern: `box v`.
+ Box(PatBox),
+
+ /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
+ Ident(PatIdent),
+
+ /// A literal pattern: `0`.
+ ///
+ /// This holds an `Expr` rather than a `Lit` because negative numbers
+ /// are represented as an `Expr::Unary`.
+ Lit(PatLit),
+
+ /// A macro in pattern position.
+ Macro(PatMacro),
+
+ /// A pattern that matches any one of a set of cases.
+ Or(PatOr),
+
+ /// A path pattern like `Color::Red`, optionally qualified with a
+ /// self-type.
+ ///
+ /// Unqualified path patterns can legally refer to variants, structs,
+ /// constants or associated constants. Qualified path patterns like
+ /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to
+ /// associated constants.
+ Path(PatPath),
+
+ /// A range pattern: `1..=2`.
+ Range(PatRange),
+
+ /// A reference pattern: `&mut var`.
+ Reference(PatReference),
+
+ /// The dots in a tuple or slice pattern: `[0, 1, ..]`
+ Rest(PatRest),
+
+ /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
+ Slice(PatSlice),
+
+ /// A struct or struct variant pattern: `Variant { x, y, .. }`.
+ Struct(PatStruct),
+
+ /// A tuple pattern: `(a, b)`.
+ Tuple(PatTuple),
+
+ /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
+ TupleStruct(PatTupleStruct),
+
+ /// A type ascription pattern: `foo: f64`.
+ Type(PatType),
+
+ /// Tokens in pattern position not interpreted by Syn.
+ Verbatim(TokenStream),
+
+ /// A pattern that matches any value: `_`.
+ Wild(PatWild),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// A box pattern: `box v`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatBox {
+ pub attrs: Vec<Attribute>,
+ pub box_token: Token![box],
+ pub pat: Box<Pat>,
+ }
+}
+
+ast_struct! {
+ /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatIdent {
+ pub attrs: Vec<Attribute>,
+ pub by_ref: Option<Token![ref]>,
+ pub mutability: Option<Token![mut]>,
+ pub ident: Ident,
+ pub subpat: Option<(Token![@], Box<Pat>)>,
+ }
+}
+
+ast_struct! {
+ /// A literal pattern: `0`.
+ ///
+ /// This holds an `Expr` rather than a `Lit` because negative numbers
+ /// are represented as an `Expr::Unary`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatLit {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A macro in pattern position.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatMacro {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ }
+}
+
+ast_struct! {
+ /// A pattern that matches any one of a set of cases.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatOr {
+ pub attrs: Vec<Attribute>,
+ pub leading_vert: Option<Token![|]>,
+ pub cases: Punctuated<Pat, Token![|]>,
+ }
+}
+
+ast_struct! {
+ /// A path pattern like `Color::Red`, optionally qualified with a
+ /// self-type.
+ ///
+ /// Unqualified path patterns can legally refer to variants, structs,
+ /// constants or associated constants. Qualified path patterns like
+ /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to
+ /// associated constants.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatPath {
+ pub attrs: Vec<Attribute>,
+ pub qself: Option<QSelf>,
+ pub path: Path,
+ }
+}
+
+ast_struct! {
+ /// A range pattern: `1..=2`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatRange {
+ pub attrs: Vec<Attribute>,
+ pub lo: Box<Expr>,
+ pub limits: RangeLimits,
+ pub hi: Box<Expr>,
+ }
+}
+
+ast_struct! {
+ /// A reference pattern: `&mut var`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatReference {
+ pub attrs: Vec<Attribute>,
+ pub and_token: Token![&],
+ pub mutability: Option<Token![mut]>,
+ pub pat: Box<Pat>,
+ }
+}
+
+ast_struct! {
+ /// The dots in a tuple or slice pattern: `[0, 1, ..]`
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatRest {
+ pub attrs: Vec<Attribute>,
+ pub dot2_token: Token![..],
+ }
+}
+
+ast_struct! {
+ /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatSlice {
+ pub attrs: Vec<Attribute>,
+ pub bracket_token: token::Bracket,
+ pub elems: Punctuated<Pat, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A struct or struct variant pattern: `Variant { x, y, .. }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatStruct {
+ pub attrs: Vec<Attribute>,
+ pub path: Path,
+ pub brace_token: token::Brace,
+ pub fields: Punctuated<FieldPat, Token![,]>,
+ pub dot2_token: Option<Token![..]>,
+ }
+}
+
+ast_struct! {
+ /// A tuple pattern: `(a, b)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatTuple {
+ pub attrs: Vec<Attribute>,
+ pub paren_token: token::Paren,
+ pub elems: Punctuated<Pat, Token![,]>,
+ }
+}
+
+ast_struct! {
+ /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatTupleStruct {
+ pub attrs: Vec<Attribute>,
+ pub path: Path,
+ pub pat: PatTuple,
+ }
+}
+
+ast_struct! {
+ /// A type ascription pattern: `foo: f64`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatType {
+ pub attrs: Vec<Attribute>,
+ pub pat: Box<Pat>,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A pattern that matches any value: `_`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct PatWild {
+ pub attrs: Vec<Attribute>,
+ pub underscore_token: Token![_],
+ }
+}
+
+ast_struct! {
+ /// A single field in a struct pattern.
+ ///
+ /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
+ /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct FieldPat {
+ pub attrs: Vec<Attribute>,
+ pub member: Member,
+ pub colon_token: Option<Token![:]>,
+ pub pat: Box<Pat>,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Pat {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Pat {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Pat::Box(this), Pat::Box(other)) => this == other,
+ (Pat::Ident(this), Pat::Ident(other)) => this == other,
+ (Pat::Lit(this), Pat::Lit(other)) => this == other,
+ (Pat::Macro(this), Pat::Macro(other)) => this == other,
+ (Pat::Or(this), Pat::Or(other)) => this == other,
+ (Pat::Path(this), Pat::Path(other)) => this == other,
+ (Pat::Range(this), Pat::Range(other)) => this == other,
+ (Pat::Reference(this), Pat::Reference(other)) => this == other,
+ (Pat::Rest(this), Pat::Rest(other)) => this == other,
+ (Pat::Slice(this), Pat::Slice(other)) => this == other,
+ (Pat::Struct(this), Pat::Struct(other)) => this == other,
+ (Pat::Tuple(this), Pat::Tuple(other)) => this == other,
+ (Pat::TupleStruct(this), Pat::TupleStruct(other)) => this == other,
+ (Pat::Type(this), Pat::Type(other)) => this == other,
+ (Pat::Verbatim(this), Pat::Verbatim(other)) => {
+ TokenStreamHelper(this) == TokenStreamHelper(other)
+ }
+ (Pat::Wild(this), Pat::Wild(other)) => this == other,
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Pat {
+ fn hash<H>(&self, hash: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ Pat::Box(pat) => {
+ hash.write_u8(0);
+ pat.hash(hash);
+ }
+ Pat::Ident(pat) => {
+ hash.write_u8(1);
+ pat.hash(hash);
+ }
+ Pat::Lit(pat) => {
+ hash.write_u8(2);
+ pat.hash(hash);
+ }
+ Pat::Macro(pat) => {
+ hash.write_u8(3);
+ pat.hash(hash);
+ }
+ Pat::Or(pat) => {
+ hash.write_u8(4);
+ pat.hash(hash);
+ }
+ Pat::Path(pat) => {
+ hash.write_u8(5);
+ pat.hash(hash);
+ }
+ Pat::Range(pat) => {
+ hash.write_u8(6);
+ pat.hash(hash);
+ }
+ Pat::Reference(pat) => {
+ hash.write_u8(7);
+ pat.hash(hash);
+ }
+ Pat::Rest(pat) => {
+ hash.write_u8(8);
+ pat.hash(hash);
+ }
+ Pat::Slice(pat) => {
+ hash.write_u8(9);
+ pat.hash(hash);
+ }
+ Pat::Struct(pat) => {
+ hash.write_u8(10);
+ pat.hash(hash);
+ }
+ Pat::Tuple(pat) => {
+ hash.write_u8(11);
+ pat.hash(hash);
+ }
+ Pat::TupleStruct(pat) => {
+ hash.write_u8(12);
+ pat.hash(hash);
+ }
+ Pat::Type(pat) => {
+ hash.write_u8(13);
+ pat.hash(hash);
+ }
+ Pat::Verbatim(pat) => {
+ hash.write_u8(14);
+ TokenStreamHelper(pat).hash(hash);
+ }
+ Pat::Wild(pat) => {
+ hash.write_u8(15);
+ pat.hash(hash);
+ }
+ Pat::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+#[cfg(feature = "parsing")]
+mod parsing {
+ use super::*;
+
+ use crate::ext::IdentExt;
+ use crate::parse::{Parse, ParseStream, Result};
+ use crate::path;
+
+ impl Parse for Pat {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Ident)
+ && ({
+ input.peek2(Token![::])
+ || input.peek2(Token![!])
+ || input.peek2(token::Brace)
+ || input.peek2(token::Paren)
+ || input.peek2(Token![..])
+ && !{
+ let ahead = input.fork();
+ ahead.parse::<Ident>()?;
+ ahead.parse::<RangeLimits>()?;
+ ahead.is_empty() || ahead.peek(Token![,])
+ }
+ })
+ || input.peek(Token![self]) && input.peek2(Token![::])
+ || lookahead.peek(Token![::])
+ || lookahead.peek(Token![<])
+ || input.peek(Token![Self])
+ || input.peek(Token![super])
+ || input.peek(Token![extern])
+ || input.peek(Token![crate])
+ {
+ pat_path_or_macro_or_struct_or_range(input)
+ } else if lookahead.peek(Token![_]) {
+ input.call(pat_wild).map(Pat::Wild)
+ } else if input.peek(Token![box]) {
+ input.call(pat_box).map(Pat::Box)
+ } else if input.peek(Token![-]) || lookahead.peek(Lit) {
+ pat_lit_or_range(input)
+ } else if lookahead.peek(Token![ref])
+ || lookahead.peek(Token![mut])
+ || input.peek(Token![self])
+ || input.peek(Ident)
+ {
+ input.call(pat_ident).map(Pat::Ident)
+ } else if lookahead.peek(Token![&]) {
+ input.call(pat_reference).map(Pat::Reference)
+ } else if lookahead.peek(token::Paren) {
+ input.call(pat_tuple).map(Pat::Tuple)
+ } else if lookahead.peek(token::Bracket) {
+ input.call(pat_slice).map(Pat::Slice)
+ } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) {
+ input.call(pat_rest).map(Pat::Rest)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+ }
+
+ fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
+ let (qself, path) = path::parsing::qpath(input, true)?;
+
+ if input.peek(Token![..]) {
+ return pat_range(input, qself, path).map(Pat::Range);
+ }
+
+ if qself.is_some() {
+ return Ok(Pat::Path(PatPath {
+ attrs: Vec::new(),
+ qself,
+ path,
+ }));
+ }
+
+ if input.peek(Token![!]) && !input.peek(Token![!=]) {
+ let mut contains_arguments = false;
+ for segment in &path.segments {
+ match segment.arguments {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => {
+ contains_arguments = true;
+ }
+ }
+ }
+
+ if !contains_arguments {
+ let bang_token: Token![!] = input.parse()?;
+ let (delimiter, tokens) = mac::parse_delimiter(input)?;
+ return Ok(Pat::Macro(PatMacro {
+ attrs: Vec::new(),
+ mac: Macro {
+ path,
+ bang_token,
+ delimiter,
+ tokens,
+ },
+ }));
+ }
+ }
+
+ if input.peek(token::Brace) {
+ pat_struct(input, path).map(Pat::Struct)
+ } else if input.peek(token::Paren) {
+ pat_tuple_struct(input, path).map(Pat::TupleStruct)
+ } else if input.peek(Token![..]) {
+ pat_range(input, qself, path).map(Pat::Range)
+ } else {
+ Ok(Pat::Path(PatPath {
+ attrs: Vec::new(),
+ qself,
+ path,
+ }))
+ }
+ }
+
+ fn pat_wild(input: ParseStream) -> Result<PatWild> {
+ Ok(PatWild {
+ attrs: Vec::new(),
+ underscore_token: input.parse()?,
+ })
+ }
+
+ fn pat_box(input: ParseStream) -> Result<PatBox> {
+ Ok(PatBox {
+ attrs: Vec::new(),
+ box_token: input.parse()?,
+ pat: input.parse()?,
+ })
+ }
+
+ fn pat_ident(input: ParseStream) -> Result<PatIdent> {
+ Ok(PatIdent {
+ attrs: Vec::new(),
+ by_ref: input.parse()?,
+ mutability: input.parse()?,
+ ident: input.call(Ident::parse_any)?,
+ subpat: {
+ if input.peek(Token![@]) {
+ let at_token: Token![@] = input.parse()?;
+ let subpat: Pat = input.parse()?;
+ Some((at_token, Box::new(subpat)))
+ } else {
+ None
+ }
+ },
+ })
+ }
+
+ fn pat_tuple_struct(input: ParseStream, path: Path) -> Result<PatTupleStruct> {
+ Ok(PatTupleStruct {
+ attrs: Vec::new(),
+ path,
+ pat: input.call(pat_tuple)?,
+ })
+ }
+
+ fn pat_struct(input: ParseStream, path: Path) -> Result<PatStruct> {
+ let content;
+ let brace_token = braced!(content in input);
+
+ let mut fields = Punctuated::new();
+ while !content.is_empty() && !content.peek(Token![..]) {
+ let value = content.call(field_pat)?;
+ fields.push_value(value);
+ if !content.peek(Token![,]) {
+ break;
+ }
+ let punct: Token![,] = content.parse()?;
+ fields.push_punct(punct);
+ }
+
+ let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) {
+ Some(content.parse()?)
+ } else {
+ None
+ };
+
+ Ok(PatStruct {
+ attrs: Vec::new(),
+ path,
+ brace_token,
+ fields,
+ dot2_token,
+ })
+ }
+
+ impl Member {
+ fn is_unnamed(&self) -> bool {
+ match *self {
+ Member::Named(_) => false,
+ Member::Unnamed(_) => true,
+ }
+ }
+ }
+
+ fn field_pat(input: ParseStream) -> Result<FieldPat> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let boxed: Option<Token![box]> = input.parse()?;
+ let by_ref: Option<Token![ref]> = input.parse()?;
+ let mutability: Option<Token![mut]> = input.parse()?;
+ let member: Member = input.parse()?;
+
+ if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
+ || member.is_unnamed()
+ {
+ return Ok(FieldPat {
+ attrs,
+ member,
+ colon_token: input.parse()?,
+ pat: input.parse()?,
+ });
+ }
+
+ let ident = match member {
+ Member::Named(ident) => ident,
+ Member::Unnamed(_) => unreachable!(),
+ };
+
+ let mut pat = Pat::Ident(PatIdent {
+ attrs: Vec::new(),
+ by_ref,
+ mutability,
+ ident: ident.clone(),
+ subpat: None,
+ });
+
+ if let Some(boxed) = boxed {
+ pat = Pat::Box(PatBox {
+ attrs: Vec::new(),
+ box_token: boxed,
+ pat: Box::new(pat),
+ });
+ }
+
+ Ok(FieldPat {
+ attrs,
+ member: Member::Named(ident),
+ colon_token: None,
+ pat: Box::new(pat),
+ })
+ }
+
+ fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatRange> {
+ Ok(PatRange {
+ attrs: Vec::new(),
+ lo: Box::new(Expr::Path(ExprPath {
+ attrs: Vec::new(),
+ qself,
+ path,
+ })),
+ limits: input.parse()?,
+ hi: input.call(pat_lit_expr)?,
+ })
+ }
+
+ fn pat_tuple(input: ParseStream) -> Result<PatTuple> {
+ let content;
+ let paren_token = parenthesized!(content in input);
+
+ let mut elems = Punctuated::new();
+ while !content.is_empty() {
+ let value: Pat = content.parse()?;
+ elems.push_value(value);
+ if content.is_empty() {
+ break;
+ }
+ let punct = content.parse()?;
+ elems.push_punct(punct);
+ }
+
+ Ok(PatTuple {
+ attrs: Vec::new(),
+ paren_token,
+ elems,
+ })
+ }
+
+ fn pat_reference(input: ParseStream) -> Result<PatReference> {
+ Ok(PatReference {
+ attrs: Vec::new(),
+ and_token: input.parse()?,
+ mutability: input.parse()?,
+ pat: input.parse()?,
+ })
+ }
+
+ fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
+ let lo = input.call(pat_lit_expr)?;
+ if input.peek(Token![..]) {
+ Ok(Pat::Range(PatRange {
+ attrs: Vec::new(),
+ lo,
+ limits: input.parse()?,
+ hi: input.call(pat_lit_expr)?,
+ }))
+ } else {
+ Ok(Pat::Lit(PatLit {
+ attrs: Vec::new(),
+ expr: lo,
+ }))
+ }
+ }
+
+ fn pat_lit_expr(input: ParseStream) -> Result<Box<Expr>> {
+ let neg: Option<Token![-]> = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ let expr = if lookahead.peek(Lit) {
+ Expr::Lit(input.parse()?)
+ } else if lookahead.peek(Ident)
+ || lookahead.peek(Token![::])
+ || lookahead.peek(Token![<])
+ || lookahead.peek(Token![self])
+ || lookahead.peek(Token![Self])
+ || lookahead.peek(Token![super])
+ || lookahead.peek(Token![extern])
+ || lookahead.peek(Token![crate])
+ {
+ Expr::Path(input.parse()?)
+ } else {
+ return Err(lookahead.error());
+ };
+
+ Ok(Box::new(if let Some(neg) = neg {
+ Expr::Unary(ExprUnary {
+ attrs: Vec::new(),
+ op: UnOp::Neg(neg),
+ expr: Box::new(expr),
+ })
+ } else {
+ expr
+ }))
+ }
+
+ fn pat_slice(input: ParseStream) -> Result<PatSlice> {
+ let content;
+ let bracket_token = bracketed!(content in input);
+
+ let mut elems = Punctuated::new();
+ while !content.is_empty() {
+ let value: Pat = content.parse()?;
+ elems.push_value(value);
+ if content.is_empty() {
+ break;
+ }
+ let punct = content.parse()?;
+ elems.push_punct(punct);
+ }
+
+ Ok(PatSlice {
+ attrs: Vec::new(),
+ bracket_token,
+ elems,
+ })
+ }
+
+ fn pat_rest(input: ParseStream) -> Result<PatRest> {
+ Ok(PatRest {
+ attrs: Vec::new(),
+ dot2_token: input.parse()?,
+ })
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ use crate::attr::FilterAttrs;
+
+ impl ToTokens for PatWild {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.underscore_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatIdent {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.by_ref.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ if let Some((at_token, subpat)) = &self.subpat {
+ at_token.to_tokens(tokens);
+ subpat.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for PatStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.path.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ self.fields.to_tokens(tokens);
+ // NOTE: We need a comma before the dot2 token if it is present.
+ if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ self.dot2_token.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for PatTupleStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.path.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.pat.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatPath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ private::print_path(tokens, &self.qself, &self.path);
+ }
+ }
+
+ impl ToTokens for PatTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.paren_token.surround(tokens, |tokens| {
+ self.elems.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for PatBox {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.box_token.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatReference {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.and_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatRest {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.dot2_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatLit {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatRange {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.lo.to_tokens(tokens);
+ match &self.limits {
+ RangeLimits::HalfOpen(t) => t.to_tokens(tokens),
+ RangeLimits::Closed(t) => t.to_tokens(tokens),
+ }
+ self.hi.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatSlice {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.bracket_token.surround(tokens, |tokens| {
+ self.elems.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for PatMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatOr {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.leading_vert.to_tokens(tokens);
+ self.cases.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for FieldPat {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ if let Some(colon_token) = &self.colon_token {
+ self.member.to_tokens(tokens);
+ colon_token.to_tokens(tokens);
+ }
+ self.pat.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn/src/path.rs b/syn/src/path.rs
new file mode 100644
index 0000000..8dda43e
--- /dev/null
+++ b/syn/src/path.rs
@@ -0,0 +1,744 @@
+use super::*;
+use crate::punctuated::Punctuated;
+
+ast_struct! {
+ /// A path at which a named item is exported: `std::collections::HashMap`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Path {
+ pub leading_colon: Option<Token![::]>,
+ pub segments: Punctuated<PathSegment, Token![::]>,
+ }
+}
+
+impl<T> From<T> for Path
+where
+ T: Into<PathSegment>,
+{
+ fn from(segment: T) -> Self {
+ let mut path = Path {
+ leading_colon: None,
+ segments: Punctuated::new(),
+ };
+ path.segments.push_value(segment.into());
+ path
+ }
+}
+
+ast_struct! {
+ /// A segment of a path together with any path arguments on that segment.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct PathSegment {
+ pub ident: Ident,
+ pub arguments: PathArguments,
+ }
+}
+
+impl<T> From<T> for PathSegment
+where
+ T: Into<Ident>,
+{
+ fn from(ident: T) -> Self {
+ PathSegment {
+ ident: ident.into(),
+ arguments: PathArguments::None,
+ }
+ }
+}
+
+ast_enum! {
+ /// Angle bracketed or parenthesized arguments of a path segment.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// ## Angle bracketed
+ ///
+ /// The `<'a, T>` in `std::slice::iter<'a, T>`.
+ ///
+ /// ## Parenthesized
+ ///
+ /// The `(A, B) -> C` in `Fn(A, B) -> C`.
+ pub enum PathArguments {
+ None,
+ /// The `<'a, T>` in `std::slice::iter<'a, T>`.
+ AngleBracketed(AngleBracketedGenericArguments),
+ /// The `(A, B) -> C` in `Fn(A, B) -> C`.
+ Parenthesized(ParenthesizedGenericArguments),
+ }
+}
+
+impl Default for PathArguments {
+ fn default() -> Self {
+ PathArguments::None
+ }
+}
+
+impl PathArguments {
+ pub fn is_empty(&self) -> bool {
+ match self {
+ PathArguments::None => true,
+ PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(),
+ PathArguments::Parenthesized(_) => false,
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ fn is_none(&self) -> bool {
+ match *self {
+ PathArguments::None => true,
+ PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
+ }
+ }
+}
+
+ast_enum! {
+ /// An individual generic argument, like `'a`, `T`, or `Item = T`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum GenericArgument {
+ /// A lifetime argument.
+ Lifetime(Lifetime),
+ /// A type argument.
+ Type(Type),
+ /// A binding (equality constraint) on an associated type: the `Item =
+ /// u8` in `Iterator<Item = u8>`.
+ Binding(Binding),
+ /// An associated type bound: `Iterator<Item: Display>`.
+ Constraint(Constraint),
+ /// A const expression. Must be inside of a block.
+ ///
+ /// NOTE: Identity expressions are represented as Type arguments, as
+ /// they are indistinguishable syntactically.
+ Const(Expr),
+ }
+}
+
+ast_struct! {
+ /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
+ /// V>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct AngleBracketedGenericArguments {
+ pub colon2_token: Option<Token![::]>,
+ pub lt_token: Token![<],
+ pub args: Punctuated<GenericArgument, Token![,]>,
+ pub gt_token: Token![>],
+ }
+}
+
+ast_struct! {
+ /// A binding (equality constraint) on an associated type: `Item = u8`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Binding {
+ pub ident: Ident,
+ pub eq_token: Token![=],
+ pub ty: Type,
+ }
+}
+
+ast_struct! {
+ /// An associated type bound: `Iterator<Item: Display>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Constraint {
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ }
+}
+
+ast_struct! {
+ /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
+ /// C`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct ParenthesizedGenericArguments {
+ pub paren_token: token::Paren,
+ /// `(A, B)`
+ pub inputs: Punctuated<Type, Token![,]>,
+ /// `C`
+ pub output: ReturnType,
+ }
+}
+
+ast_struct! {
+ /// The explicit Self type in a qualified path: the `T` in `<T as
+ /// Display>::fmt`.
+ ///
+ /// The actual path, including the trait and the associated item, is stored
+ /// separately. The `position` field represents the index of the associated
+ /// item qualified with this Self type.
+ ///
+ /// ```text
+ /// <Vec<T> as a::b::Trait>::AssociatedItem
+ /// ^~~~~~ ~~~~~~~~~~~~~~^
+ /// ty position = 3
+ ///
+ /// <Vec<T>>::AssociatedItem
+ /// ^~~~~~ ^
+ /// ty position = 0
+ /// ```
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct QSelf {
+ pub lt_token: Token![<],
+ pub ty: Box<Type>,
+ pub position: usize,
+ pub as_token: Option<Token![as]>,
+ pub gt_token: Token![>],
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ #[cfg(feature = "full")]
+ use crate::expr;
+ use crate::ext::IdentExt;
+ use crate::parse::{Parse, ParseStream, Result};
+
+ impl Parse for Path {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse_helper(input, false)
+ }
+ }
+
+ impl Parse for GenericArgument {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Lifetime) && !input.peek2(Token![+]) {
+ return Ok(GenericArgument::Lifetime(input.parse()?));
+ }
+
+ if input.peek(Ident) && input.peek2(Token![=]) {
+ return Ok(GenericArgument::Binding(input.parse()?));
+ }
+
+ #[cfg(feature = "full")]
+ {
+ if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
+ return Ok(GenericArgument::Constraint(input.parse()?));
+ }
+
+ if input.peek(Lit) {
+ let lit = input.parse()?;
+ return Ok(GenericArgument::Const(Expr::Lit(lit)));
+ }
+
+ if input.peek(token::Brace) {
+ let block = input.call(expr::parsing::expr_block)?;
+ return Ok(GenericArgument::Const(Expr::Block(block)));
+ }
+ }
+
+ input.parse().map(GenericArgument::Type)
+ }
+ }
+
+ impl Parse for AngleBracketedGenericArguments {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(AngleBracketedGenericArguments {
+ colon2_token: input.parse()?,
+ lt_token: input.parse()?,
+ args: {
+ let mut args = Punctuated::new();
+ loop {
+ if input.peek(Token![>]) {
+ break;
+ }
+ let value = input.parse()?;
+ args.push_value(value);
+ if input.peek(Token![>]) {
+ break;
+ }
+ let punct = input.parse()?;
+ args.push_punct(punct);
+ }
+ args
+ },
+ gt_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for ParenthesizedGenericArguments {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(ParenthesizedGenericArguments {
+ paren_token: parenthesized!(content in input),
+ inputs: content.parse_terminated(Type::parse)?,
+ output: input.call(ReturnType::without_plus)?,
+ })
+ }
+ }
+
+ impl Parse for PathSegment {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse_helper(input, false)
+ }
+ }
+
+ impl PathSegment {
+ fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
+ if input.peek(Token![super])
+ || input.peek(Token![self])
+ || input.peek(Token![crate])
+ || input.peek(Token![extern])
+ {
+ let ident = input.call(Ident::parse_any)?;
+ return Ok(PathSegment::from(ident));
+ }
+
+ let ident = if input.peek(Token![Self]) {
+ input.call(Ident::parse_any)?
+ } else {
+ input.parse()?
+ };
+
+ if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
+ || input.peek(Token![::]) && input.peek3(Token![<])
+ {
+ Ok(PathSegment {
+ ident,
+ arguments: PathArguments::AngleBracketed(input.parse()?),
+ })
+ } else {
+ Ok(PathSegment::from(ident))
+ }
+ }
+ }
+
+ impl Parse for Binding {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Binding {
+ ident: input.parse()?,
+ eq_token: input.parse()?,
+ ty: input.parse()?,
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Parse for Constraint {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Constraint {
+ ident: input.parse()?,
+ colon_token: input.parse()?,
+ bounds: {
+ let mut bounds = Punctuated::new();
+ loop {
+ if input.peek(Token![,]) || input.peek(Token![>]) {
+ break;
+ }
+ let value = input.parse()?;
+ bounds.push_value(value);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ let punct = input.parse()?;
+ bounds.push_punct(punct);
+ }
+ bounds
+ },
+ })
+ }
+ }
+
+ impl Path {
+ /// Parse a `Path` containing no path arguments on any of its segments.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{Path, Result, Token};
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// // A simplified single `use` statement like:
+ /// //
+ /// // use std::collections::HashMap;
+ /// //
+ /// // Note that generic parameters are not allowed in a `use` statement
+ /// // so the following must not be accepted.
+ /// //
+ /// // use a::<b>::c;
+ /// struct SingleUse {
+ /// use_token: Token![use],
+ /// path: Path,
+ /// }
+ ///
+ /// impl Parse for SingleUse {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// Ok(SingleUse {
+ /// use_token: input.parse()?,
+ /// path: input.call(Path::parse_mod_style)?,
+ /// })
+ /// }
+ /// }
+ /// ```
+ pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
+ Ok(Path {
+ leading_colon: input.parse()?,
+ segments: {
+ let mut segments = Punctuated::new();
+ loop {
+ if !input.peek(Ident)
+ && !input.peek(Token![super])
+ && !input.peek(Token![self])
+ && !input.peek(Token![Self])
+ && !input.peek(Token![crate])
+ && !input.peek(Token![extern])
+ {
+ break;
+ }
+ let ident = Ident::parse_any(input)?;
+ segments.push_value(PathSegment::from(ident));
+ if !input.peek(Token![::]) {
+ break;
+ }
+ let punct = input.parse()?;
+ segments.push_punct(punct);
+ }
+ if segments.is_empty() {
+ return Err(input.error("expected path"));
+ } else if segments.trailing_punct() {
+ return Err(input.error("expected path segment"));
+ }
+ segments
+ },
+ })
+ }
+
+ /// Determines whether this is a path of length 1 equal to the given
+ /// ident.
+ ///
+ /// For them to compare equal, it must be the case that:
+ ///
+ /// - the path has no leading colon,
+ /// - the number of path segments is 1,
+ /// - the first path segment has no angle bracketed or parenthesized
+ /// path arguments, and
+ /// - the ident of the first path segment is equal to the given one.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{Attribute, Error, Meta, NestedMeta, Result};
+ /// # use std::iter::FromIterator;
+ ///
+ /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> {
+ /// if attr.path.is_ident("serde") {
+ /// match attr.parse_meta()? {
+ /// Meta::List(meta) => Ok(Vec::from_iter(meta.nested)),
+ /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
+ /// }
+ /// } else {
+ /// Ok(Vec::new())
+ /// }
+ /// }
+ /// ```
+ pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
+ where
+ Ident: PartialEq<I>,
+ {
+ match self.get_ident() {
+ Some(id) => id == ident,
+ None => false,
+ }
+ }
+
+ /// If this path consists of a single ident, returns the ident.
+ ///
+ /// A path is considered an ident if:
+ ///
+ /// - the path has no leading colon,
+ /// - the number of path segments is 1, and
+ /// - the first path segment has no angle bracketed or parenthesized
+ /// path arguments.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ pub fn get_ident(&self) -> Option<&Ident> {
+ if self.leading_colon.is_none()
+ && self.segments.len() == 1
+ && self.segments[0].arguments.is_none()
+ {
+ Some(&self.segments[0].ident)
+ } else {
+ None
+ }
+ }
+
+ fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
+ Ok(Path {
+ leading_colon: input.parse()?,
+ segments: {
+ let mut segments = Punctuated::new();
+ let value = PathSegment::parse_helper(input, expr_style)?;
+ segments.push_value(value);
+ while input.peek(Token![::]) {
+ let punct: Token![::] = input.parse()?;
+ segments.push_punct(punct);
+ let value = PathSegment::parse_helper(input, expr_style)?;
+ segments.push_value(value);
+ }
+ segments
+ },
+ })
+ }
+ }
+
+ pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
+ if input.peek(Token![<]) {
+ let lt_token: Token![<] = input.parse()?;
+ let this: Type = input.parse()?;
+ let path = if input.peek(Token![as]) {
+ let as_token: Token![as] = input.parse()?;
+ let path: Path = input.parse()?;
+ Some((as_token, path))
+ } else {
+ None
+ };
+ let gt_token: Token![>] = input.parse()?;
+ let colon2_token: Token![::] = input.parse()?;
+ let mut rest = Punctuated::new();
+ loop {
+ let path = PathSegment::parse_helper(input, expr_style)?;
+ rest.push_value(path);
+ if !input.peek(Token![::]) {
+ break;
+ }
+ let punct: Token![::] = input.parse()?;
+ rest.push_punct(punct);
+ }
+ let (position, as_token, path) = match path {
+ Some((as_token, mut path)) => {
+ let pos = path.segments.len();
+ path.segments.push_punct(colon2_token);
+ path.segments.extend(rest.into_pairs());
+ (pos, Some(as_token), path)
+ }
+ None => {
+ let path = Path {
+ leading_colon: Some(colon2_token),
+ segments: rest,
+ };
+ (0, None, path)
+ }
+ };
+ let qself = QSelf {
+ lt_token,
+ ty: Box::new(this),
+ position,
+ as_token,
+ gt_token,
+ };
+ Ok((Some(qself), path))
+ } else {
+ let path = Path::parse_helper(input, expr_style)?;
+ Ok((None, path))
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ use crate::print::TokensOrDefault;
+
+ impl ToTokens for Path {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.leading_colon.to_tokens(tokens);
+ self.segments.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PathSegment {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.arguments.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PathArguments {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(arguments) => {
+ arguments.to_tokens(tokens);
+ }
+ PathArguments::Parenthesized(arguments) => {
+ arguments.to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for GenericArgument {
+ #[allow(clippy::match_same_arms)]
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
+ GenericArgument::Type(ty) => ty.to_tokens(tokens),
+ GenericArgument::Binding(tb) => tb.to_tokens(tokens),
+ GenericArgument::Constraint(tc) => tc.to_tokens(tokens),
+ GenericArgument::Const(e) => match *e {
+ Expr::Lit(_) => e.to_tokens(tokens),
+
+ // NOTE: We should probably support parsing blocks with only
+ // expressions in them without the full feature for const
+ // generics.
+ #[cfg(feature = "full")]
+ Expr::Block(_) => e.to_tokens(tokens),
+
+ // ERROR CORRECTION: Add braces to make sure that the
+ // generated code is valid.
+ _ => token::Brace::default().surround(tokens, |tokens| {
+ e.to_tokens(tokens);
+ }),
+ },
+ }
+ }
+ }
+
+ impl ToTokens for AngleBracketedGenericArguments {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.colon2_token.to_tokens(tokens);
+ self.lt_token.to_tokens(tokens);
+
+ // 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
+ let mut trailing_or_empty = true;
+ for param in self.args.pairs() {
+ match **param.value() {
+ GenericArgument::Lifetime(_) => {
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ GenericArgument::Type(_)
+ | GenericArgument::Binding(_)
+ | GenericArgument::Constraint(_)
+ | GenericArgument::Const(_) => {}
+ }
+ }
+ for param in self.args.pairs() {
+ match **param.value() {
+ GenericArgument::Type(_) | GenericArgument::Const(_) => {
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ GenericArgument::Lifetime(_)
+ | GenericArgument::Binding(_)
+ | GenericArgument::Constraint(_) => {}
+ }
+ }
+ for param in self.args.pairs() {
+ match **param.value() {
+ GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ param.to_tokens(tokens);
+ }
+ GenericArgument::Lifetime(_)
+ | GenericArgument::Type(_)
+ | GenericArgument::Const(_) => {}
+ }
+ }
+
+ self.gt_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Binding {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Constraint {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ParenthesizedGenericArguments {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.inputs.to_tokens(tokens);
+ });
+ self.output.to_tokens(tokens);
+ }
+ }
+
+ impl private {
+ pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
+ let qself = match qself {
+ Some(qself) => qself,
+ None => {
+ path.to_tokens(tokens);
+ return;
+ }
+ };
+ qself.lt_token.to_tokens(tokens);
+ qself.ty.to_tokens(tokens);
+
+ let pos = if qself.position > 0 && qself.position >= path.segments.len() {
+ path.segments.len() - 1
+ } else {
+ qself.position
+ };
+ let mut segments = path.segments.pairs();
+ if pos > 0 {
+ TokensOrDefault(&qself.as_token).to_tokens(tokens);
+ path.leading_colon.to_tokens(tokens);
+ for (i, segment) in segments.by_ref().take(pos).enumerate() {
+ if i + 1 == pos {
+ segment.value().to_tokens(tokens);
+ qself.gt_token.to_tokens(tokens);
+ segment.punct().to_tokens(tokens);
+ } else {
+ segment.to_tokens(tokens);
+ }
+ }
+ } else {
+ qself.gt_token.to_tokens(tokens);
+ path.leading_colon.to_tokens(tokens);
+ }
+ for segment in segments {
+ segment.to_tokens(tokens);
+ }
+ }
+ }
+}
diff --git a/syn/src/print.rs b/syn/src/print.rs
new file mode 100644
index 0000000..da4e07e
--- /dev/null
+++ b/syn/src/print.rs
@@ -0,0 +1,16 @@
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+
+pub struct TokensOrDefault<'a, T: 'a>(pub &'a Option<T>);
+
+impl<'a, T> ToTokens for TokensOrDefault<'a, T>
+where
+ T: ToTokens + Default,
+{
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self.0 {
+ Some(t) => t.to_tokens(tokens),
+ None => T::default().to_tokens(tokens),
+ }
+ }
+}
diff --git a/syn/src/punctuated.rs b/syn/src/punctuated.rs
new file mode 100644
index 0000000..38c7bf4
--- /dev/null
+++ b/syn/src/punctuated.rs
@@ -0,0 +1,918 @@
+//! A punctuated sequence of syntax tree nodes separated by punctuation.
+//!
+//! Lots of things in Rust are punctuated sequences.
+//!
+//! - The fields of a struct are `Punctuated<Field, Token![,]>`.
+//! - The segments of a path are `Punctuated<PathSegment, Token![::]>`.
+//! - The bounds on a generic parameter are `Punctuated<TypeParamBound,
+//! Token![+]>`.
+//! - The arguments to a function call are `Punctuated<Expr, Token![,]>`.
+//!
+//! This module provides a common representation for these punctuated sequences
+//! in the form of the [`Punctuated<T, P>`] type. We store a vector of pairs of
+//! syntax tree node + punctuation, where every node in the sequence is followed
+//! by punctuation except for possibly the final one.
+//!
+//! [`Punctuated<T, P>`]: struct.Punctuated.html
+//!
+//! ```text
+//! a_function_call(arg1, arg2, arg3);
+//! ~~~~^ ~~~~^ ~~~~
+//! ```
+
+#[cfg(feature = "extra-traits")]
+use std::fmt::{self, Debug};
+#[cfg(any(feature = "full", feature = "derive"))]
+use std::iter;
+use std::iter::FromIterator;
+use std::ops::{Index, IndexMut};
+use std::option;
+use std::slice;
+use std::vec;
+
+#[cfg(feature = "parsing")]
+use crate::parse::{Parse, ParseStream, Result};
+#[cfg(feature = "parsing")]
+use crate::token::Token;
+
+/// A punctuated sequence of syntax tree nodes of type `T` separated by
+/// punctuation of type `P`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: self
+#[cfg_attr(feature = "extra-traits", derive(Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct Punctuated<T, P> {
+ inner: Vec<(T, P)>,
+ last: Option<Box<T>>,
+}
+
+impl<T, P> Punctuated<T, P> {
+ /// Creates an empty punctuated sequence.
+ pub fn new() -> Punctuated<T, P> {
+ Punctuated {
+ inner: Vec::new(),
+ last: None,
+ }
+ }
+
+ /// Determines whether this punctuated sequence is empty, meaning it
+ /// contains no syntax tree nodes or punctuation.
+ pub fn is_empty(&self) -> bool {
+ self.inner.len() == 0 && self.last.is_none()
+ }
+
+ /// Returns the number of syntax tree nodes in this punctuated sequence.
+ ///
+ /// This is the number of nodes of type `T`, not counting the punctuation of
+ /// type `P`.
+ pub fn len(&self) -> usize {
+ self.inner.len() + if self.last.is_some() { 1 } else { 0 }
+ }
+
+ /// Borrows the first element in this sequence.
+ pub fn first(&self) -> Option<&T> {
+ self.iter().next()
+ }
+
+ /// Borrows the last element in this sequence.
+ pub fn last(&self) -> Option<&T> {
+ if self.last.is_some() {
+ self.last.as_ref().map(Box::as_ref)
+ } else {
+ self.inner.last().map(|pair| &pair.0)
+ }
+ }
+
+ /// Mutably borrows the last element in this sequence.
+ pub fn last_mut(&mut self) -> Option<&mut T> {
+ if self.last.is_some() {
+ self.last.as_mut().map(Box::as_mut)
+ } else {
+ self.inner.last_mut().map(|pair| &mut pair.0)
+ }
+ }
+
+ /// Returns an iterator over borrowed syntax tree nodes of type `&T`.
+ pub fn iter(&self) -> Iter<T> {
+ Iter {
+ inner: Box::new(PrivateIter {
+ inner: self.inner.iter(),
+ last: self.last.as_ref().map(Box::as_ref).into_iter(),
+ }),
+ }
+ }
+
+ /// Returns an iterator over mutably borrowed syntax tree nodes of type
+ /// `&mut T`.
+ pub fn iter_mut(&mut self) -> IterMut<T> {
+ IterMut {
+ inner: Box::new(PrivateIterMut {
+ inner: self.inner.iter_mut(),
+ last: self.last.as_mut().map(Box::as_mut).into_iter(),
+ }),
+ }
+ }
+
+ /// Returns an iterator over the contents of this sequence as borrowed
+ /// punctuated pairs.
+ pub fn pairs(&self) -> Pairs<T, P> {
+ Pairs {
+ inner: self.inner.iter(),
+ last: self.last.as_ref().map(Box::as_ref).into_iter(),
+ }
+ }
+
+ /// Returns an iterator over the contents of this sequence as mutably
+ /// borrowed punctuated pairs.
+ pub fn pairs_mut(&mut self) -> PairsMut<T, P> {
+ PairsMut {
+ inner: self.inner.iter_mut(),
+ last: self.last.as_mut().map(Box::as_mut).into_iter(),
+ }
+ }
+
+ /// Returns an iterator over the contents of this sequence as owned
+ /// punctuated pairs.
+ pub fn into_pairs(self) -> IntoPairs<T, P> {
+ IntoPairs {
+ inner: self.inner.into_iter(),
+ last: self.last.map(|t| *t).into_iter(),
+ }
+ }
+
+ /// Appends a syntax tree node onto the end of this punctuated sequence. The
+ /// sequence must previously have a trailing punctuation.
+ ///
+ /// Use [`push`] instead if the punctuated sequence may or may not already
+ /// have trailing punctuation.
+ ///
+ /// [`push`]: Punctuated::push
+ ///
+ /// # Panics
+ ///
+ /// Panics if the sequence does not already have a trailing punctuation when
+ /// this method is called.
+ pub fn push_value(&mut self, value: T) {
+ assert!(self.empty_or_trailing());
+ self.last = Some(Box::new(value));
+ }
+
+ /// Appends a trailing punctuation onto the end of this punctuated sequence.
+ /// The sequence must be non-empty and must not already have trailing
+ /// punctuation.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the sequence is empty or already has a trailing punctuation.
+ pub fn push_punct(&mut self, punctuation: P) {
+ assert!(self.last.is_some());
+ let last = self.last.take().unwrap();
+ self.inner.push((*last, punctuation));
+ }
+
+ /// Removes the last punctuated pair from this sequence, or `None` if the
+ /// sequence is empty.
+ pub fn pop(&mut self) -> Option<Pair<T, P>> {
+ if self.last.is_some() {
+ self.last.take().map(|t| Pair::End(*t))
+ } else {
+ self.inner.pop().map(|(t, d)| Pair::Punctuated(t, d))
+ }
+ }
+
+ /// Determines whether this punctuated sequence ends with a trailing
+ /// punctuation.
+ pub fn trailing_punct(&self) -> bool {
+ self.last.is_none() && !self.is_empty()
+ }
+
+ /// Returns true if either this `Punctuated` is empty, or it has a trailing
+ /// punctuation.
+ ///
+ /// Equivalent to `punctuated.is_empty() || punctuated.trailing_punct()`.
+ pub fn empty_or_trailing(&self) -> bool {
+ self.last.is_none()
+ }
+
+ /// Appends a syntax tree node onto the end of this punctuated sequence.
+ ///
+ /// If there is not a trailing punctuation in this sequence when this method
+ /// is called, the default value of punctuation type `P` is inserted before
+ /// the given value of type `T`.
+ pub fn push(&mut self, value: T)
+ where
+ P: Default,
+ {
+ if !self.empty_or_trailing() {
+ self.push_punct(Default::default());
+ }
+ self.push_value(value);
+ }
+
+ /// Inserts an element at position `index`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index` is greater than the number of elements previously in
+ /// this punctuated sequence.
+ pub fn insert(&mut self, index: usize, value: T)
+ where
+ P: Default,
+ {
+ assert!(index <= self.len());
+
+ if index == self.len() {
+ self.push(value);
+ } else {
+ self.inner.insert(index, (value, Default::default()));
+ }
+ }
+
+ /// Parses zero or more occurrences of `T` separated by punctuation of type
+ /// `P`, with optional trailing punctuation.
+ ///
+ /// Parsing continues until the end of this parse stream. The entire content
+ /// of this parse stream must consist of `T` and `P`.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_terminated(input: ParseStream) -> Result<Self>
+ where
+ T: Parse,
+ P: Parse,
+ {
+ Self::parse_terminated_with(input, T::parse)
+ }
+
+ /// Parses zero or more occurrences of `T` using the given parse function,
+ /// separated by punctuation of type `P`, with optional trailing
+ /// punctuation.
+ ///
+ /// Like [`parse_terminated`], the entire content of this stream is expected
+ /// to be parsed.
+ ///
+ /// [`parse_terminated`]: Punctuated::parse_terminated
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_terminated_with(
+ input: ParseStream,
+ parser: fn(ParseStream) -> Result<T>,
+ ) -> Result<Self>
+ where
+ P: Parse,
+ {
+ let mut punctuated = Punctuated::new();
+
+ loop {
+ if input.is_empty() {
+ break;
+ }
+ let value = parser(input)?;
+ punctuated.push_value(value);
+ if input.is_empty() {
+ break;
+ }
+ let punct = input.parse()?;
+ punctuated.push_punct(punct);
+ }
+
+ Ok(punctuated)
+ }
+
+ /// Parses one or more occurrences of `T` separated by punctuation of type
+ /// `P`, not accepting trailing punctuation.
+ ///
+ /// Parsing continues as long as punctuation `P` is present at the head of
+ /// the stream. This method returns upon parsing a `T` and observing that it
+ /// is not followed by a `P`, even if there are remaining tokens in the
+ /// stream.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_separated_nonempty(input: ParseStream) -> Result<Self>
+ where
+ T: Parse,
+ P: Token + Parse,
+ {
+ Self::parse_separated_nonempty_with(input, T::parse)
+ }
+
+ /// Parses one or more occurrences of `T` using the given parse function,
+ /// separated by punctuation of type `P`, not accepting trailing
+ /// punctuation.
+ ///
+ /// Like [`parse_separated_nonempty`], may complete early without parsing
+ /// the entire content of this stream.
+ ///
+ /// [`parse_separated_nonempty`]: Punctuated::parse_separated_nonempty
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ #[cfg(feature = "parsing")]
+ pub fn parse_separated_nonempty_with(
+ input: ParseStream,
+ parser: fn(ParseStream) -> Result<T>,
+ ) -> Result<Self>
+ where
+ P: Token + Parse,
+ {
+ let mut punctuated = Punctuated::new();
+
+ loop {
+ let value = parser(input)?;
+ punctuated.push_value(value);
+ if !P::peek(input.cursor()) {
+ break;
+ }
+ let punct = input.parse()?;
+ punctuated.push_punct(punct);
+ }
+
+ Ok(punctuated)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl<T: Debug, P: Debug> Debug for Punctuated<T, P> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut list = f.debug_list();
+ for (t, p) in &self.inner {
+ list.entry(t);
+ list.entry(p);
+ }
+ if let Some(last) = &self.last {
+ list.entry(last);
+ }
+ list.finish()
+ }
+}
+
+impl<T, P> FromIterator<T> for Punctuated<T, P>
+where
+ P: Default,
+{
+ fn from_iter<I: IntoIterator<Item = T>>(i: I) -> Self {
+ let mut ret = Punctuated::new();
+ ret.extend(i);
+ ret
+ }
+}
+
+impl<T, P> Extend<T> for Punctuated<T, P>
+where
+ P: Default,
+{
+ fn extend<I: IntoIterator<Item = T>>(&mut self, i: I) {
+ for value in i {
+ self.push(value);
+ }
+ }
+}
+
+impl<T, P> FromIterator<Pair<T, P>> for Punctuated<T, P> {
+ fn from_iter<I: IntoIterator<Item = Pair<T, P>>>(i: I) -> Self {
+ let mut ret = Punctuated::new();
+ ret.extend(i);
+ ret
+ }
+}
+
+impl<T, P> Extend<Pair<T, P>> for Punctuated<T, P> {
+ fn extend<I: IntoIterator<Item = Pair<T, P>>>(&mut self, i: I) {
+ assert!(self.empty_or_trailing());
+ let mut nomore = false;
+ for pair in i {
+ if nomore {
+ panic!("Punctuated extended with items after a Pair::End");
+ }
+ match pair {
+ Pair::Punctuated(a, b) => self.inner.push((a, b)),
+ Pair::End(a) => {
+ self.last = Some(Box::new(a));
+ nomore = true;
+ }
+ }
+ }
+ }
+}
+
+impl<T, P> IntoIterator for Punctuated<T, P> {
+ type Item = T;
+ type IntoIter = IntoIter<T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ let mut elements = Vec::with_capacity(self.len());
+ elements.extend(self.inner.into_iter().map(|pair| pair.0));
+ elements.extend(self.last.map(|t| *t));
+
+ IntoIter {
+ inner: elements.into_iter(),
+ }
+ }
+}
+
+impl<'a, T, P> IntoIterator for &'a Punctuated<T, P> {
+ type Item = &'a T;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Punctuated::iter(self)
+ }
+}
+
+impl<'a, T, P> IntoIterator for &'a mut Punctuated<T, P> {
+ type Item = &'a mut T;
+ type IntoIter = IterMut<'a, T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Punctuated::iter_mut(self)
+ }
+}
+
+impl<T, P> Default for Punctuated<T, P> {
+ fn default() -> Self {
+ Punctuated::new()
+ }
+}
+
+/// An iterator over borrowed pairs of type `Pair<&T, &P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: self
+pub struct Pairs<'a, T: 'a, P: 'a> {
+ inner: slice::Iter<'a, (T, P)>,
+ last: option::IntoIter<&'a T>,
+}
+
+impl<'a, T, P> Iterator for Pairs<'a, T, P> {
+ type Item = Pair<&'a T, &'a P>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|(t, p)| Pair::Punctuated(t, p))
+ .or_else(|| self.last.next().map(Pair::End))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+
+impl<'a, T, P> DoubleEndedIterator for Pairs<'a, T, P> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.last
+ .next()
+ .map(Pair::End)
+ .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p)))
+ }
+}
+
+impl<'a, T, P> ExactSizeIterator for Pairs<'a, T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+// No Clone bound on T or P.
+impl<'a, T, P> Clone for Pairs<'a, T, P> {
+ fn clone(&self) -> Self {
+ Pairs {
+ inner: self.inner.clone(),
+ last: self.last.clone(),
+ }
+ }
+}
+
+/// An iterator over mutably borrowed pairs of type `Pair<&mut T, &mut P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: self
+pub struct PairsMut<'a, T: 'a, P: 'a> {
+ inner: slice::IterMut<'a, (T, P)>,
+ last: option::IntoIter<&'a mut T>,
+}
+
+impl<'a, T, P> Iterator for PairsMut<'a, T, P> {
+ type Item = Pair<&'a mut T, &'a mut P>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|(t, p)| Pair::Punctuated(t, p))
+ .or_else(|| self.last.next().map(Pair::End))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+
+impl<'a, T, P> DoubleEndedIterator for PairsMut<'a, T, P> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.last
+ .next()
+ .map(Pair::End)
+ .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p)))
+ }
+}
+
+impl<'a, T, P> ExactSizeIterator for PairsMut<'a, T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+/// An iterator over owned pairs of type `Pair<T, P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: self
+#[derive(Clone)]
+pub struct IntoPairs<T, P> {
+ inner: vec::IntoIter<(T, P)>,
+ last: option::IntoIter<T>,
+}
+
+impl<T, P> Iterator for IntoPairs<T, P> {
+ type Item = Pair<T, P>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|(t, p)| Pair::Punctuated(t, p))
+ .or_else(|| self.last.next().map(Pair::End))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+
+impl<T, P> DoubleEndedIterator for IntoPairs<T, P> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.last
+ .next()
+ .map(Pair::End)
+ .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p)))
+ }
+}
+
+impl<T, P> ExactSizeIterator for IntoPairs<T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+/// An iterator over owned values of type `T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: self
+#[derive(Clone)]
+pub struct IntoIter<T> {
+ inner: vec::IntoIter<T>,
+}
+
+impl<T> Iterator for IntoIter<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+
+impl<T> DoubleEndedIterator for IntoIter<T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.inner.next_back()
+ }
+}
+
+impl<T> ExactSizeIterator for IntoIter<T> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+/// An iterator over borrowed values of type `&T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: self
+pub struct Iter<'a, T: 'a> {
+ // The `Item = &'a T` needs to be specified to support rustc 1.31 and older.
+ // On modern compilers we would be able to write just IterTrait<'a, T> where
+ // Item can be inferred unambiguously from the supertrait.
+ inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
+}
+
+trait IterTrait<'a, T: 'a>:
+ DoubleEndedIterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>
+{
+ fn clone_box(&self) -> Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>;
+}
+
+struct PrivateIter<'a, T: 'a, P: 'a> {
+ inner: slice::Iter<'a, (T, P)>,
+ last: option::IntoIter<&'a T>,
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+pub(crate) fn empty_punctuated_iter<'a, T>() -> Iter<'a, T> {
+ Iter {
+ inner: Box::new(iter::empty()),
+ }
+}
+
+// No Clone bound on T.
+impl<'a, T> Clone for Iter<'a, T> {
+ fn clone(&self) -> Self {
+ Iter {
+ inner: self.inner.clone_box(),
+ }
+ }
+}
+
+impl<'a, T> Iterator for Iter<'a, T> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+
+impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.inner.next_back()
+ }
+}
+
+impl<'a, T> ExactSizeIterator for Iter<'a, T> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+impl<'a, T, P> Iterator for PrivateIter<'a, T, P> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|pair| &pair.0)
+ .or_else(|| self.last.next())
+ }
+}
+
+impl<'a, T, P> DoubleEndedIterator for PrivateIter<'a, T, P> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.last
+ .next()
+ .or_else(|| self.inner.next_back().map(|pair| &pair.0))
+ }
+}
+
+impl<'a, T, P> ExactSizeIterator for PrivateIter<'a, T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+// No Clone bound on T or P.
+impl<'a, T, P> Clone for PrivateIter<'a, T, P> {
+ fn clone(&self) -> Self {
+ PrivateIter {
+ inner: self.inner.clone(),
+ last: self.last.clone(),
+ }
+ }
+}
+
+impl<'a, T: 'a, I: 'a> IterTrait<'a, T> for I
+where
+ I: DoubleEndedIterator<Item = &'a T> + ExactSizeIterator<Item = &'a T> + Clone,
+{
+ fn clone_box(&self) -> Box<dyn IterTrait<'a, T, Item = &'a T> + 'a> {
+ Box::new(self.clone())
+ }
+}
+
+/// An iterator over mutably borrowed values of type `&mut T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: self
+pub struct IterMut<'a, T: 'a> {
+ inner: Box<dyn IterMutTrait<'a, T, Item = &'a mut T> + 'a>,
+}
+
+trait IterMutTrait<'a, T: 'a>:
+ DoubleEndedIterator<Item = &'a mut T> + ExactSizeIterator<Item = &'a mut T>
+{
+}
+
+struct PrivateIterMut<'a, T: 'a, P: 'a> {
+ inner: slice::IterMut<'a, (T, P)>,
+ last: option::IntoIter<&'a mut T>,
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+pub(crate) fn empty_punctuated_iter_mut<'a, T>() -> IterMut<'a, T> {
+ IterMut {
+ inner: Box::new(iter::empty()),
+ }
+}
+
+impl<'a, T> Iterator for IterMut<'a, T> {
+ type Item = &'a mut T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+
+impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.inner.next_back()
+ }
+}
+
+impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+impl<'a, T, P> Iterator for PrivateIterMut<'a, T, P> {
+ type Item = &'a mut T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|pair| &mut pair.0)
+ .or_else(|| self.last.next())
+ }
+}
+
+impl<'a, T, P> DoubleEndedIterator for PrivateIterMut<'a, T, P> {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.last
+ .next()
+ .or_else(|| self.inner.next_back().map(|pair| &mut pair.0))
+ }
+}
+
+impl<'a, T, P> ExactSizeIterator for PrivateIterMut<'a, T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+impl<'a, T: 'a, I: 'a> IterMutTrait<'a, T> for I where
+ I: DoubleEndedIterator<Item = &'a mut T> + ExactSizeIterator<Item = &'a mut T>
+{
+}
+
+/// A single syntax tree node of type `T` followed by its trailing punctuation
+/// of type `P` if any.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: self
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub enum Pair<T, P> {
+ Punctuated(T, P),
+ End(T),
+}
+
+impl<T, P> Pair<T, P> {
+ /// Extracts the syntax tree node from this punctuated pair, discarding the
+ /// following punctuation.
+ pub fn into_value(self) -> T {
+ match self {
+ Pair::Punctuated(t, _) | Pair::End(t) => t,
+ }
+ }
+
+ /// Borrows the syntax tree node from this punctuated pair.
+ pub fn value(&self) -> &T {
+ match self {
+ Pair::Punctuated(t, _) | Pair::End(t) => t,
+ }
+ }
+
+ /// Mutably borrows the syntax tree node from this punctuated pair.
+ pub fn value_mut(&mut self) -> &mut T {
+ match self {
+ Pair::Punctuated(t, _) | Pair::End(t) => t,
+ }
+ }
+
+ /// Borrows the punctuation from this punctuated pair, unless this pair is
+ /// the final one and there is no trailing punctuation.
+ pub fn punct(&self) -> Option<&P> {
+ match self {
+ Pair::Punctuated(_, d) => Some(d),
+ Pair::End(_) => None,
+ }
+ }
+
+ /// Creates a punctuated pair out of a syntax tree node and an optional
+ /// following punctuation.
+ pub fn new(t: T, d: Option<P>) -> Self {
+ match d {
+ Some(d) => Pair::Punctuated(t, d),
+ None => Pair::End(t),
+ }
+ }
+
+ /// Produces this punctuated pair as a tuple of syntax tree node and
+ /// optional following punctuation.
+ pub fn into_tuple(self) -> (T, Option<P>) {
+ match self {
+ Pair::Punctuated(t, d) => (t, Some(d)),
+ Pair::End(t) => (t, None),
+ }
+ }
+}
+
+impl<T, P> Index<usize> for Punctuated<T, P> {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ if index == self.len() - 1 {
+ match &self.last {
+ Some(t) => t,
+ None => &self.inner[index].0,
+ }
+ } else {
+ &self.inner[index].0
+ }
+ }
+}
+
+impl<T, P> IndexMut<usize> for Punctuated<T, P> {
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ if index == self.len() - 1 {
+ match &mut self.last {
+ Some(t) => t,
+ None => &mut self.inner[index].0,
+ }
+ } else {
+ &mut self.inner[index].0
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl<T, P> ToTokens for Punctuated<T, P>
+ where
+ T: ToTokens,
+ P: ToTokens,
+ {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.pairs())
+ }
+ }
+
+ impl<T, P> ToTokens for Pair<T, P>
+ where
+ T: ToTokens,
+ P: ToTokens,
+ {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ Pair::Punctuated(a, b) => {
+ a.to_tokens(tokens);
+ b.to_tokens(tokens);
+ }
+ Pair::End(a) => a.to_tokens(tokens),
+ }
+ }
+ }
+}
diff --git a/syn/src/sealed.rs b/syn/src/sealed.rs
new file mode 100644
index 0000000..0b11bc9
--- /dev/null
+++ b/syn/src/sealed.rs
@@ -0,0 +1,4 @@
+#[cfg(feature = "parsing")]
+pub mod lookahead {
+ pub trait Sealed: Copy {}
+}
diff --git a/syn/src/span.rs b/syn/src/span.rs
new file mode 100644
index 0000000..27a7fe8
--- /dev/null
+++ b/syn/src/span.rs
@@ -0,0 +1,67 @@
+use proc_macro2::Span;
+
+pub trait IntoSpans<S> {
+ fn into_spans(self) -> S;
+}
+
+impl IntoSpans<[Span; 1]> for Span {
+ fn into_spans(self) -> [Span; 1] {
+ [self]
+ }
+}
+
+impl IntoSpans<[Span; 2]> for Span {
+ fn into_spans(self) -> [Span; 2] {
+ [self, self]
+ }
+}
+
+impl IntoSpans<[Span; 3]> for Span {
+ fn into_spans(self) -> [Span; 3] {
+ [self, self, self]
+ }
+}
+
+impl IntoSpans<[Span; 1]> for [Span; 1] {
+ fn into_spans(self) -> [Span; 1] {
+ self
+ }
+}
+
+impl IntoSpans<[Span; 2]> for [Span; 2] {
+ fn into_spans(self) -> [Span; 2] {
+ self
+ }
+}
+
+impl IntoSpans<[Span; 3]> for [Span; 3] {
+ fn into_spans(self) -> [Span; 3] {
+ self
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub trait FromSpans: Sized {
+ fn from_spans(spans: &[Span]) -> Self;
+}
+
+#[cfg(feature = "parsing")]
+impl FromSpans for [Span; 1] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0]]
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl FromSpans for [Span; 2] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0], spans[1]]
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl FromSpans for [Span; 3] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0], spans[1], spans[2]]
+ }
+}
diff --git a/syn/src/spanned.rs b/syn/src/spanned.rs
new file mode 100644
index 0000000..71ffe26
--- /dev/null
+++ b/syn/src/spanned.rs
@@ -0,0 +1,114 @@
+//! A trait that can provide the `Span` of the complete contents of a syntax
+//! tree node.
+//!
+//! *This module is available if Syn is built with both the `"parsing"` and
+//! `"printing"` features.*
+//!
+//! <br>
+//!
+//! # Example
+//!
+//! Suppose in a procedural macro we have a [`Type`] that we want to assert
+//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
+//! of a struct for which we are deriving a trait implementation, and we need to
+//! be able to pass a reference to one of those fields across threads.
+//!
+//! [`Type`]: ../enum.Type.html
+//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+//!
+//! If the field type does *not* implement `Sync` as required, we want the
+//! compiler to report an error pointing out exactly which type it was.
+//!
+//! The following macro code takes a variable `ty` of type `Type` and produces a
+//! static assertion that `Sync` is implemented for that type.
+//!
+//! ```
+//! # extern crate proc_macro;
+//! #
+//! use proc_macro::TokenStream;
+//! use proc_macro2::Span;
+//! use quote::quote_spanned;
+//! use syn::Type;
+//! use syn::spanned::Spanned;
+//!
+//! # const IGNORE_TOKENS: &str = stringify! {
+//! #[proc_macro_derive(MyMacro)]
+//! # };
+//! pub fn my_macro(input: TokenStream) -> TokenStream {
+//! # let ty = get_a_type();
+//! /* ... */
+//!
+//! let assert_sync = quote_spanned! {ty.span()=>
+//! struct _AssertSync where #ty: Sync;
+//! };
+//!
+//! /* ... */
+//! # input
+//! }
+//! #
+//! # fn get_a_type() -> Type {
+//! # unimplemented!()
+//! # }
+//! ```
+//!
+//! By inserting this `assert_sync` fragment into the output code generated by
+//! our macro, the user's code will fail to compile if `ty` does not implement
+//! `Sync`. The errors they would see look like the following.
+//!
+//! ```text
+//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
+//! --> src/main.rs:10:21
+//! |
+//! 10 | bad_field: *const i32,
+//! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
+//! ```
+//!
+//! In this technique, using the `Type`'s span for the error message makes the
+//! error appear in the correct place underlining the right type.
+//!
+//! <br>
+//!
+//! # Limitations
+//!
+//! The underlying [`proc_macro::Span::join`] method is nightly-only. When
+//! called from within a procedural macro in a nightly compiler, `Spanned` will
+//! use `join` to produce the intended span. When not using a nightly compiler,
+//! only the span of the *first token* of the syntax tree node is returned.
+//!
+//! In the common case of wanting to use the joined span as the span of a
+//! `syn::Error`, consider instead using [`syn::Error::new_spanned`] which is
+//! able to span the error correctly under the complete syntax tree node without
+//! needing the unstable `join`.
+//!
+//! [`syn::Error::new_spanned`]: crate::Error::new_spanned
+
+use proc_macro2::Span;
+use quote::spanned::Spanned as ToTokens;
+
+/// A trait that can provide the `Span` of the complete contents of a syntax
+/// tree node.
+///
+/// This trait is automatically implemented for all types that implement
+/// [`ToTokens`] from the `quote` crate, as well as for `Span` itself.
+///
+/// [`ToTokens`]: quote::ToTokens
+///
+/// See the [module documentation] for an example.
+///
+/// [module documentation]: self
+///
+/// *This trait is available if Syn is built with both the `"parsing"` and
+/// `"printing"` features.*
+pub trait Spanned {
+ /// Returns a `Span` covering the complete contents of this syntax tree
+ /// node, or [`Span::call_site()`] if this node is empty.
+ ///
+ /// [`Span::call_site()`]: proc_macro2::Span::call_site
+ fn span(&self) -> Span;
+}
+
+impl<T: ?Sized + ToTokens> Spanned for T {
+ fn span(&self) -> Span {
+ self.__span()
+ }
+}
diff --git a/syn/src/stmt.rs b/syn/src/stmt.rs
new file mode 100644
index 0000000..acee5a3
--- /dev/null
+++ b/syn/src/stmt.rs
@@ -0,0 +1,333 @@
+use super::*;
+
+ast_struct! {
+ /// A braced block containing Rust statements.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Block {
+ pub brace_token: token::Brace,
+ /// Statements in a block
+ pub stmts: Vec<Stmt>,
+ }
+}
+
+ast_enum! {
+ /// A statement, usually ending in a semicolon.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub enum Stmt {
+ /// A local (let) binding.
+ Local(Local),
+
+ /// An item definition.
+ Item(Item),
+
+ /// Expr without trailing semicolon.
+ Expr(Expr),
+
+ /// Expression with trailing semicolon.
+ Semi(Expr, Token![;]),
+ }
+}
+
+ast_struct! {
+ /// A local `let` binding: `let x: u64 = s.parse()?`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Local {
+ pub attrs: Vec<Attribute>,
+ pub let_token: Token![let],
+ pub pat: Pat,
+ pub init: Option<(Token![=], Box<Expr>)>,
+ pub semi_token: Token![;],
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::parse::discouraged::Speculative;
+ use crate::parse::{Parse, ParseStream, Result};
+ use crate::punctuated::Punctuated;
+ use proc_macro2::TokenStream;
+
+ impl Block {
+ /// Parse the body of a block as zero or more statements, possibly
+ /// including one trailing expression.
+ ///
+ /// *This function is available if Syn is built with the `"parsing"`
+ /// feature.*
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token};
+ /// use syn::parse::{Parse, ParseStream};
+ ///
+ /// // Parse a function with no generics or parameter list.
+ /// //
+ /// // fn playground {
+ /// // let mut x = 1;
+ /// // x += 1;
+ /// // println!("{}", x);
+ /// // }
+ /// struct MiniFunction {
+ /// attrs: Vec<Attribute>,
+ /// fn_token: Token![fn],
+ /// name: Ident,
+ /// brace_token: token::Brace,
+ /// stmts: Vec<Stmt>,
+ /// }
+ ///
+ /// impl Parse for MiniFunction {
+ /// fn parse(input: ParseStream) -> Result<Self> {
+ /// let outer_attrs = input.call(Attribute::parse_outer)?;
+ /// let fn_token: Token![fn] = input.parse()?;
+ /// let name: Ident = input.parse()?;
+ ///
+ /// let content;
+ /// let brace_token = braced!(content in input);
+ /// let inner_attrs = content.call(Attribute::parse_inner)?;
+ /// let stmts = content.call(Block::parse_within)?;
+ ///
+ /// Ok(MiniFunction {
+ /// attrs: {
+ /// let mut attrs = outer_attrs;
+ /// attrs.extend(inner_attrs);
+ /// attrs
+ /// },
+ /// fn_token,
+ /// name,
+ /// brace_token,
+ /// stmts,
+ /// })
+ /// }
+ /// }
+ /// ```
+ pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
+ let mut stmts = Vec::new();
+ loop {
+ while let Some(semi) = input.parse::<Option<Token![;]>>()? {
+ stmts.push(Stmt::Semi(Expr::Verbatim(TokenStream::new()), semi));
+ }
+ if input.is_empty() {
+ break;
+ }
+ let s = parse_stmt(input, true)?;
+ let requires_semicolon = if let Stmt::Expr(s) = &s {
+ expr::requires_terminator(s)
+ } else {
+ false
+ };
+ stmts.push(s);
+ if input.is_empty() {
+ break;
+ } else if requires_semicolon {
+ return Err(input.error("unexpected token"));
+ }
+ }
+ Ok(stmts)
+ }
+ }
+
+ impl Parse for Block {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(Block {
+ brace_token: braced!(content in input),
+ stmts: content.call(Block::parse_within)?,
+ })
+ }
+ }
+
+ impl Parse for Stmt {
+ fn parse(input: ParseStream) -> Result<Self> {
+ parse_stmt(input, false)
+ }
+ }
+
+ fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
+ let mut attrs = input.call(Attribute::parse_outer)?;
+
+ // brace-style macros; paren and bracket macros get parsed as
+ // expression statements.
+ let ahead = input.fork();
+ if let Ok(path) = ahead.call(Path::parse_mod_style) {
+ if ahead.peek(Token![!]) && (ahead.peek2(token::Brace) || ahead.peek2(Ident)) {
+ input.advance_to(&ahead);
+ return stmt_mac(input, attrs, path);
+ }
+ }
+
+ if input.peek(Token![let]) {
+ stmt_local(input, attrs).map(Stmt::Local)
+ } else if input.peek(Token![pub])
+ || input.peek(Token![crate]) && !input.peek2(Token![::])
+ || input.peek(Token![extern]) && !input.peek2(Token![::])
+ || input.peek(Token![use])
+ || input.peek(Token![static]) && (input.peek2(Token![mut]) || input.peek2(Ident))
+ || input.peek(Token![const])
+ || input.peek(Token![unsafe]) && !input.peek2(token::Brace)
+ || input.peek(Token![async])
+ && (input.peek2(Token![unsafe])
+ || input.peek2(Token![extern])
+ || input.peek2(Token![fn]))
+ || input.peek(Token![fn])
+ || input.peek(Token![mod])
+ || input.peek(Token![type])
+ || input.peek(item::parsing::existential) && input.peek2(Token![type])
+ || input.peek(Token![struct])
+ || input.peek(Token![enum])
+ || input.peek(Token![union]) && input.peek2(Ident)
+ || input.peek(Token![auto]) && input.peek2(Token![trait])
+ || input.peek(Token![trait])
+ || input.peek(Token![default])
+ && (input.peek2(Token![unsafe]) || input.peek2(Token![impl]))
+ || input.peek(Token![impl])
+ || input.peek(Token![macro])
+ {
+ let mut item: Item = input.parse()?;
+ attrs.extend(item.replace_attrs(Vec::new()));
+ item.replace_attrs(attrs);
+ Ok(Stmt::Item(item))
+ } else {
+ stmt_expr(input, allow_nosemi, attrs)
+ }
+ }
+
+ fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt> {
+ let bang_token: Token![!] = input.parse()?;
+ let ident: Option<Ident> = input.parse()?;
+ let (delimiter, tokens) = mac::parse_delimiter(input)?;
+ let semi_token: Option<Token![;]> = input.parse()?;
+
+ Ok(Stmt::Item(Item::Macro(ItemMacro {
+ attrs,
+ ident,
+ mac: Macro {
+ path,
+ bang_token,
+ delimiter,
+ tokens,
+ },
+ semi_token,
+ })))
+ }
+
+ fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> {
+ Ok(Local {
+ attrs,
+ let_token: input.parse()?,
+ pat: {
+ let leading_vert: Option<Token![|]> = input.parse()?;
+ let mut pat: Pat = input.parse()?;
+ if leading_vert.is_some()
+ || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
+ {
+ let mut cases = Punctuated::new();
+ cases.push_value(pat);
+ while input.peek(Token![|])
+ && !input.peek(Token![||])
+ && !input.peek(Token![|=])
+ {
+ let punct = input.parse()?;
+ cases.push_punct(punct);
+ let pat: Pat = input.parse()?;
+ cases.push_value(pat);
+ }
+ pat = Pat::Or(PatOr {
+ attrs: Vec::new(),
+ leading_vert,
+ cases,
+ });
+ }
+ if input.peek(Token![:]) {
+ let colon_token: Token![:] = input.parse()?;
+ let ty: Type = input.parse()?;
+ pat = Pat::Type(PatType {
+ attrs: Vec::new(),
+ pat: Box::new(pat),
+ colon_token,
+ ty: Box::new(ty),
+ });
+ }
+ pat
+ },
+ init: {
+ if input.peek(Token![=]) {
+ let eq_token: Token![=] = input.parse()?;
+ let init: Expr = input.parse()?;
+ Some((eq_token, Box::new(init)))
+ } else {
+ None
+ }
+ },
+ semi_token: input.parse()?,
+ })
+ }
+
+ fn stmt_expr(
+ input: ParseStream,
+ allow_nosemi: bool,
+ mut attrs: Vec<Attribute>,
+ ) -> Result<Stmt> {
+ let mut e = expr::parsing::expr_early(input)?;
+
+ attrs.extend(e.replace_attrs(Vec::new()));
+ e.replace_attrs(attrs);
+
+ if input.peek(Token![;]) {
+ return Ok(Stmt::Semi(e, input.parse()?));
+ }
+
+ if allow_nosemi || !expr::requires_terminator(&e) {
+ Ok(Stmt::Expr(e))
+ } else {
+ Err(input.error("expected semicolon"))
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for Block {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(&self.stmts);
+ });
+ }
+ }
+
+ impl ToTokens for Stmt {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ Stmt::Local(local) => local.to_tokens(tokens),
+ Stmt::Item(item) => item.to_tokens(tokens),
+ Stmt::Expr(expr) => expr.to_tokens(tokens),
+ Stmt::Semi(expr, semi) => {
+ expr.to_tokens(tokens);
+ semi.to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for Local {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
+ self.let_token.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ if let Some((eq_token, init)) = &self.init {
+ eq_token.to_tokens(tokens);
+ init.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn/src/thread.rs b/syn/src/thread.rs
new file mode 100644
index 0000000..9e5d8ad
--- /dev/null
+++ b/syn/src/thread.rs
@@ -0,0 +1,41 @@
+use std::fmt::{self, Debug};
+use std::thread::{self, ThreadId};
+
+/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value
+/// of type T only from the original thread on which the ThreadBound was
+/// constructed.
+pub struct ThreadBound<T> {
+ value: T,
+ thread_id: ThreadId,
+}
+
+unsafe impl<T> Sync for ThreadBound<T> {}
+
+// Send bound requires Copy, as otherwise Drop could run in the wrong place.
+unsafe impl<T: Copy> Send for ThreadBound<T> {}
+
+impl<T> ThreadBound<T> {
+ pub fn new(value: T) -> Self {
+ ThreadBound {
+ value,
+ thread_id: thread::current().id(),
+ }
+ }
+
+ pub fn get(&self) -> Option<&T> {
+ if thread::current().id() == self.thread_id {
+ Some(&self.value)
+ } else {
+ None
+ }
+ }
+}
+
+impl<T: Debug> Debug for ThreadBound<T> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match self.get() {
+ Some(value) => Debug::fmt(value, formatter),
+ None => formatter.write_str("unknown"),
+ }
+ }
+}
diff --git a/syn/src/token.rs b/syn/src/token.rs
new file mode 100644
index 0000000..a9f787a
--- /dev/null
+++ b/syn/src/token.rs
@@ -0,0 +1,956 @@
+//! Tokens representing Rust punctuation, keywords, and delimiters.
+//!
+//! The type names in this module can be difficult to keep straight, so we
+//! prefer to use the [`Token!`] macro instead. This is a type-macro that
+//! expands to the token type of the given token.
+//!
+//! [`Token!`]: ../macro.Token.html
+//!
+//! # Example
+//!
+//! The [`ItemStatic`] syntax tree node is defined like this.
+//!
+//! [`ItemStatic`]: ../struct.ItemStatic.html
+//!
+//! ```
+//! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility};
+//! #
+//! pub struct ItemStatic {
+//! pub attrs: Vec<Attribute>,
+//! pub vis: Visibility,
+//! pub static_token: Token![static],
+//! pub mutability: Option<Token![mut]>,
+//! pub ident: Ident,
+//! pub colon_token: Token![:],
+//! pub ty: Box<Type>,
+//! pub eq_token: Token![=],
+//! pub expr: Box<Expr>,
+//! pub semi_token: Token![;],
+//! }
+//! ```
+//!
+//! # Parsing
+//!
+//! Keywords and punctuation can be parsed through the [`ParseStream::parse`]
+//! method. Delimiter tokens are parsed using the [`parenthesized!`],
+//! [`bracketed!`] and [`braced!`] macros.
+//!
+//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse
+//! [`parenthesized!`]: ../macro.parenthesized.html
+//! [`bracketed!`]: ../macro.bracketed.html
+//! [`braced!`]: ../macro.braced.html
+//!
+//! ```
+//! use syn::{Attribute, Result};
+//! use syn::parse::{Parse, ParseStream};
+//! #
+//! # enum ItemStatic {}
+//!
+//! // Parse the ItemStatic struct shown above.
+//! impl Parse for ItemStatic {
+//! fn parse(input: ParseStream) -> Result<Self> {
+//! # use syn::ItemStatic;
+//! # fn parse(input: ParseStream) -> Result<ItemStatic> {
+//! Ok(ItemStatic {
+//! attrs: input.call(Attribute::parse_outer)?,
+//! vis: input.parse()?,
+//! static_token: input.parse()?,
+//! mutability: input.parse()?,
+//! ident: input.parse()?,
+//! colon_token: input.parse()?,
+//! ty: input.parse()?,
+//! eq_token: input.parse()?,
+//! expr: input.parse()?,
+//! semi_token: input.parse()?,
+//! })
+//! # }
+//! # unimplemented!()
+//! }
+//! }
+//! ```
+//!
+//! # Other operations
+//!
+//! Every keyword and punctuation token supports the following operations.
+//!
+//! - [Peeking] — `input.peek(Token![...])`
+//!
+//! - [Parsing] — `input.parse::<Token![...]>()?`
+//!
+//! - [Printing] — `quote!( ... #the_token ... )`
+//!
+//! - Construction from a [`Span`] — `let the_token = Token![...](sp)`
+//!
+//! - Field access to its span — `let sp = the_token.span`
+//!
+//! [Peeking]: ../parse/struct.ParseBuffer.html#method.peek
+//! [Parsing]: ../parse/struct.ParseBuffer.html#method.parse
+//! [Printing]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html
+//! [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html
+
+use std;
+#[cfg(feature = "extra-traits")]
+use std::cmp;
+#[cfg(feature = "extra-traits")]
+use std::fmt::{self, Debug};
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+use std::ops::{Deref, DerefMut};
+
+#[cfg(feature = "parsing")]
+use proc_macro2::Delimiter;
+#[cfg(any(feature = "parsing", feature = "printing"))]
+use proc_macro2::Ident;
+use proc_macro2::Span;
+#[cfg(feature = "printing")]
+use proc_macro2::TokenStream;
+#[cfg(feature = "printing")]
+use quote::{ToTokens, TokenStreamExt};
+
+use self::private::WithSpan;
+#[cfg(feature = "parsing")]
+use crate::buffer::Cursor;
+#[cfg(feature = "parsing")]
+use crate::error::Result;
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "parsing")]
+use crate::lifetime::Lifetime;
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "parsing")]
+use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
+#[cfg(feature = "parsing")]
+use crate::lookahead;
+#[cfg(feature = "parsing")]
+use crate::parse::{Parse, ParseStream};
+use crate::span::IntoSpans;
+
+/// Marker trait for types that represent single tokens.
+///
+/// This trait is sealed and cannot be implemented for types outside of Syn.
+#[cfg(feature = "parsing")]
+pub trait Token: private::Sealed {
+ // Not public API.
+ #[doc(hidden)]
+ fn peek(cursor: Cursor) -> bool;
+
+ // Not public API.
+ #[doc(hidden)]
+ fn display() -> &'static str;
+}
+
+mod private {
+ use proc_macro2::Span;
+
+ #[cfg(feature = "parsing")]
+ pub trait Sealed {}
+
+ /// Support writing `token.span` rather than `token.spans[0]` on tokens that
+ /// hold a single span.
+ #[repr(C)]
+ pub struct WithSpan {
+ pub span: Span,
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl private::Sealed for Ident {}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "parsing")]
+fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
+ use crate::parse::Unexpected;
+ use std::cell::Cell;
+ use std::rc::Rc;
+
+ let scope = Span::call_site();
+ let unexpected = Rc::new(Cell::new(Unexpected::None));
+ let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected);
+ peek(&buffer)
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! impl_token {
+ ($name:ident $display:expr) => {
+ #[cfg(feature = "parsing")]
+ impl Token for $name {
+ fn peek(cursor: Cursor) -> bool {
+ fn peek(input: ParseStream) -> bool {
+ <$name as Parse>::parse(input).is_ok()
+ }
+ peek_impl(cursor, peek)
+ }
+
+ fn display() -> &'static str {
+ $display
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl private::Sealed for $name {}
+ };
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(Lifetime "lifetime");
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(Lit "literal");
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(LitStr "string literal");
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(LitByteStr "byte string literal");
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(LitByte "byte literal");
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(LitChar "character literal");
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(LitInt "integer literal");
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(LitFloat "floating point literal");
+#[cfg(any(feature = "full", feature = "derive"))]
+impl_token!(LitBool "boolean literal");
+
+// Not public API.
+#[doc(hidden)]
+#[cfg(feature = "parsing")]
+pub trait CustomToken {
+ fn peek(cursor: Cursor) -> bool;
+ fn display() -> &'static str;
+}
+
+#[cfg(feature = "parsing")]
+impl<T: CustomToken> private::Sealed for T {}
+
+#[cfg(feature = "parsing")]
+impl<T: CustomToken> Token for T {
+ fn peek(cursor: Cursor) -> bool {
+ <Self as CustomToken>::peek(cursor)
+ }
+
+ fn display() -> &'static str {
+ <Self as CustomToken>::display()
+ }
+}
+
+macro_rules! define_keywords {
+ ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
+ $(
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[$doc]
+ ///
+ /// Don't try to remember the name of this type &mdash; use the
+ /// [`Token!`] macro instead.
+ ///
+ /// [`Token!`]: crate::token
+ pub struct $name {
+ pub span: Span,
+ }
+
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
+ $name {
+ span: span.into_spans()[0],
+ }
+ }
+
+ impl std::default::Default for $name {
+ fn default() -> Self {
+ $name {
+ span: Span::call_site(),
+ }
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl Debug for $name {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(stringify!($name))
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl cmp::Eq for $name {}
+
+ #[cfg(feature = "extra-traits")]
+ impl PartialEq for $name {
+ fn eq(&self, _other: &$name) -> bool {
+ true
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl Hash for $name {
+ fn hash<H: Hasher>(&self, _state: &mut H) {}
+ }
+
+ #[cfg(feature = "printing")]
+ impl ToTokens for $name {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ printing::keyword($token, self.span, tokens);
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl Parse for $name {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok($name {
+ span: parsing::keyword(input, $token)?,
+ })
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl Token for $name {
+ fn peek(cursor: Cursor) -> bool {
+ parsing::peek_keyword(cursor, $token)
+ }
+
+ fn display() -> &'static str {
+ concat!("`", $token, "`")
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl private::Sealed for $name {}
+ )*
+ };
+}
+
+macro_rules! impl_deref_if_len_is_1 {
+ ($name:ident/1) => {
+ impl Deref for $name {
+ type Target = WithSpan;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*(self as *const Self as *const WithSpan) }
+ }
+ }
+
+ impl DerefMut for $name {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe { &mut *(self as *mut Self as *mut WithSpan) }
+ }
+ }
+ };
+
+ ($name:ident/$len:tt) => {};
+}
+
+macro_rules! define_punctuation_structs {
+ ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
+ $(
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[repr(C)]
+ #[$doc]
+ ///
+ /// Don't try to remember the name of this type &mdash; use the
+ /// [`Token!`] macro instead.
+ ///
+ /// [`Token!`]: crate::token
+ pub struct $name {
+ pub spans: [Span; $len],
+ }
+
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
+ $name {
+ spans: spans.into_spans(),
+ }
+ }
+
+ impl std::default::Default for $name {
+ fn default() -> Self {
+ $name {
+ spans: [Span::call_site(); $len],
+ }
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl Debug for $name {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(stringify!($name))
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl cmp::Eq for $name {}
+
+ #[cfg(feature = "extra-traits")]
+ impl PartialEq for $name {
+ fn eq(&self, _other: &$name) -> bool {
+ true
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl Hash for $name {
+ fn hash<H: Hasher>(&self, _state: &mut H) {}
+ }
+
+ impl_deref_if_len_is_1!($name/$len);
+ )*
+ };
+}
+
+macro_rules! define_punctuation {
+ ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
+ $(
+ define_punctuation_structs! {
+ $token pub struct $name/$len #[$doc]
+ }
+
+ #[cfg(feature = "printing")]
+ impl ToTokens for $name {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ printing::punct($token, &self.spans, tokens);
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl Parse for $name {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok($name {
+ spans: parsing::punct(input, $token)?,
+ })
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl Token for $name {
+ fn peek(cursor: Cursor) -> bool {
+ parsing::peek_punct(cursor, $token)
+ }
+
+ fn display() -> &'static str {
+ concat!("`", $token, "`")
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl private::Sealed for $name {}
+ )*
+ };
+}
+
+macro_rules! define_delimiters {
+ ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
+ $(
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[$doc]
+ pub struct $name {
+ pub span: Span,
+ }
+
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
+ $name {
+ span: span.into_spans()[0],
+ }
+ }
+
+ impl std::default::Default for $name {
+ fn default() -> Self {
+ $name {
+ span: Span::call_site(),
+ }
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl Debug for $name {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(stringify!($name))
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl cmp::Eq for $name {}
+
+ #[cfg(feature = "extra-traits")]
+ impl PartialEq for $name {
+ fn eq(&self, _other: &$name) -> bool {
+ true
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl Hash for $name {
+ fn hash<H: Hasher>(&self, _state: &mut H) {}
+ }
+
+ impl $name {
+ #[cfg(feature = "printing")]
+ pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
+ where
+ F: FnOnce(&mut TokenStream),
+ {
+ printing::delim($token, self.span, tokens, f);
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl private::Sealed for $name {}
+ )*
+ };
+}
+
+define_punctuation_structs! {
+ "_" pub struct Underscore/1 /// `_`
+}
+
+#[cfg(feature = "printing")]
+impl ToTokens for Underscore {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append(Ident::new("_", self.span));
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Parse for Underscore {
+ fn parse(input: ParseStream) -> Result<Self> {
+ input.step(|cursor| {
+ if let Some((ident, rest)) = cursor.ident() {
+ if ident == "_" {
+ return Ok((Underscore(ident.span()), rest));
+ }
+ }
+ if let Some((punct, rest)) = cursor.punct() {
+ if punct.as_char() == '_' {
+ return Ok((Underscore(punct.span()), rest));
+ }
+ }
+ Err(cursor.error("expected `_`"))
+ })
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Token for Underscore {
+ fn peek(cursor: Cursor) -> bool {
+ if let Some((ident, _rest)) = cursor.ident() {
+ return ident == "_";
+ }
+ if let Some((punct, _rest)) = cursor.punct() {
+ return punct.as_char() == '_';
+ }
+ false
+ }
+
+ fn display() -> &'static str {
+ "`_`"
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl private::Sealed for Underscore {}
+
+#[cfg(feature = "parsing")]
+impl Token for Paren {
+ fn peek(cursor: Cursor) -> bool {
+ lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
+ }
+
+ fn display() -> &'static str {
+ "parentheses"
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Token for Brace {
+ fn peek(cursor: Cursor) -> bool {
+ lookahead::is_delimiter(cursor, Delimiter::Brace)
+ }
+
+ fn display() -> &'static str {
+ "curly braces"
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Token for Bracket {
+ fn peek(cursor: Cursor) -> bool {
+ lookahead::is_delimiter(cursor, Delimiter::Bracket)
+ }
+
+ fn display() -> &'static str {
+ "square brackets"
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl Token for Group {
+ fn peek(cursor: Cursor) -> bool {
+ lookahead::is_delimiter(cursor, Delimiter::None)
+ }
+
+ fn display() -> &'static str {
+ "invisible group"
+ }
+}
+
+define_keywords! {
+ "abstract" pub struct Abstract /// `abstract`
+ "as" pub struct As /// `as`
+ "async" pub struct Async /// `async`
+ "auto" pub struct Auto /// `auto`
+ "await" pub struct Await /// `await`
+ "become" pub struct Become /// `become`
+ "box" pub struct Box /// `box`
+ "break" pub struct Break /// `break`
+ "const" pub struct Const /// `const`
+ "continue" pub struct Continue /// `continue`
+ "crate" pub struct Crate /// `crate`
+ "default" pub struct Default /// `default`
+ "do" pub struct Do /// `do`
+ "dyn" pub struct Dyn /// `dyn`
+ "else" pub struct Else /// `else`
+ "enum" pub struct Enum /// `enum`
+ "extern" pub struct Extern /// `extern`
+ "final" pub struct Final /// `final`
+ "fn" pub struct Fn /// `fn`
+ "for" pub struct For /// `for`
+ "if" pub struct If /// `if`
+ "impl" pub struct Impl /// `impl`
+ "in" pub struct In /// `in`
+ "let" pub struct Let /// `let`
+ "loop" pub struct Loop /// `loop`
+ "macro" pub struct Macro /// `macro`
+ "match" pub struct Match /// `match`
+ "mod" pub struct Mod /// `mod`
+ "move" pub struct Move /// `move`
+ "mut" pub struct Mut /// `mut`
+ "override" pub struct Override /// `override`
+ "priv" pub struct Priv /// `priv`
+ "pub" pub struct Pub /// `pub`
+ "ref" pub struct Ref /// `ref`
+ "return" pub struct Return /// `return`
+ "Self" pub struct SelfType /// `Self`
+ "self" pub struct SelfValue /// `self`
+ "static" pub struct Static /// `static`
+ "struct" pub struct Struct /// `struct`
+ "super" pub struct Super /// `super`
+ "trait" pub struct Trait /// `trait`
+ "try" pub struct Try /// `try`
+ "type" pub struct Type /// `type`
+ "typeof" pub struct Typeof /// `typeof`
+ "union" pub struct Union /// `union`
+ "unsafe" pub struct Unsafe /// `unsafe`
+ "unsized" pub struct Unsized /// `unsized`
+ "use" pub struct Use /// `use`
+ "virtual" pub struct Virtual /// `virtual`
+ "where" pub struct Where /// `where`
+ "while" pub struct While /// `while`
+ "yield" pub struct Yield /// `yield`
+}
+
+define_punctuation! {
+ "+" pub struct Add/1 /// `+`
+ "+=" pub struct AddEq/2 /// `+=`
+ "&" pub struct And/1 /// `&`
+ "&&" pub struct AndAnd/2 /// `&&`
+ "&=" pub struct AndEq/2 /// `&=`
+ "@" pub struct At/1 /// `@`
+ "!" pub struct Bang/1 /// `!`
+ "^" pub struct Caret/1 /// `^`
+ "^=" pub struct CaretEq/2 /// `^=`
+ ":" pub struct Colon/1 /// `:`
+ "::" pub struct Colon2/2 /// `::`
+ "," pub struct Comma/1 /// `,`
+ "/" pub struct Div/1 /// `/`
+ "/=" pub struct DivEq/2 /// `/=`
+ "$" pub struct Dollar/1 /// `$`
+ "." pub struct Dot/1 /// `.`
+ ".." pub struct Dot2/2 /// `..`
+ "..." pub struct Dot3/3 /// `...`
+ "..=" pub struct DotDotEq/3 /// `..=`
+ "=" pub struct Eq/1 /// `=`
+ "==" pub struct EqEq/2 /// `==`
+ ">=" pub struct Ge/2 /// `>=`
+ ">" pub struct Gt/1 /// `>`
+ "<=" pub struct Le/2 /// `<=`
+ "<" pub struct Lt/1 /// `<`
+ "*=" pub struct MulEq/2 /// `*=`
+ "!=" pub struct Ne/2 /// `!=`
+ "|" pub struct Or/1 /// `|`
+ "|=" pub struct OrEq/2 /// `|=`
+ "||" pub struct OrOr/2 /// `||`
+ "#" pub struct Pound/1 /// `#`
+ "?" pub struct Question/1 /// `?`
+ "->" pub struct RArrow/2 /// `->`
+ "<-" pub struct LArrow/2 /// `<-`
+ "%" pub struct Rem/1 /// `%`
+ "%=" pub struct RemEq/2 /// `%=`
+ "=>" pub struct FatArrow/2 /// `=>`
+ ";" pub struct Semi/1 /// `;`
+ "<<" pub struct Shl/2 /// `<<`
+ "<<=" pub struct ShlEq/3 /// `<<=`
+ ">>" pub struct Shr/2 /// `>>`
+ ">>=" pub struct ShrEq/3 /// `>>=`
+ "*" pub struct Star/1 /// `*`
+ "-" pub struct Sub/1 /// `-`
+ "-=" pub struct SubEq/2 /// `-=`
+ "~" pub struct Tilde/1 /// `~`
+}
+
+define_delimiters! {
+ "{" pub struct Brace /// `{...}`
+ "[" pub struct Bracket /// `[...]`
+ "(" pub struct Paren /// `(...)`
+ " " pub struct Group /// None-delimited group
+}
+
+macro_rules! export_token_macro {
+ ($($await_rule:tt)*) => {
+ /// A type-macro that expands to the name of the Rust type representation of a
+ /// given token.
+ ///
+ /// See the [token module] documentation for details and examples.
+ ///
+ /// [token module]: crate::token
+ // Unfortunate duplication due to a rustdoc bug.
+ // https://github.com/rust-lang/rust/issues/45939
+ #[macro_export]
+ macro_rules! Token {
+ (abstract) => { $crate::token::Abstract };
+ (as) => { $crate::token::As };
+ (async) => { $crate::token::Async };
+ (auto) => { $crate::token::Auto };
+ $($await_rule => { $crate::token::Await };)*
+ (become) => { $crate::token::Become };
+ (box) => { $crate::token::Box };
+ (break) => { $crate::token::Break };
+ (const) => { $crate::token::Const };
+ (continue) => { $crate::token::Continue };
+ (crate) => { $crate::token::Crate };
+ (default) => { $crate::token::Default };
+ (do) => { $crate::token::Do };
+ (dyn) => { $crate::token::Dyn };
+ (else) => { $crate::token::Else };
+ (enum) => { $crate::token::Enum };
+ (extern) => { $crate::token::Extern };
+ (final) => { $crate::token::Final };
+ (fn) => { $crate::token::Fn };
+ (for) => { $crate::token::For };
+ (if) => { $crate::token::If };
+ (impl) => { $crate::token::Impl };
+ (in) => { $crate::token::In };
+ (let) => { $crate::token::Let };
+ (loop) => { $crate::token::Loop };
+ (macro) => { $crate::token::Macro };
+ (match) => { $crate::token::Match };
+ (mod) => { $crate::token::Mod };
+ (move) => { $crate::token::Move };
+ (mut) => { $crate::token::Mut };
+ (override) => { $crate::token::Override };
+ (priv) => { $crate::token::Priv };
+ (pub) => { $crate::token::Pub };
+ (ref) => { $crate::token::Ref };
+ (return) => { $crate::token::Return };
+ (Self) => { $crate::token::SelfType };
+ (self) => { $crate::token::SelfValue };
+ (static) => { $crate::token::Static };
+ (struct) => { $crate::token::Struct };
+ (super) => { $crate::token::Super };
+ (trait) => { $crate::token::Trait };
+ (try) => { $crate::token::Try };
+ (type) => { $crate::token::Type };
+ (typeof) => { $crate::token::Typeof };
+ (union) => { $crate::token::Union };
+ (unsafe) => { $crate::token::Unsafe };
+ (unsized) => { $crate::token::Unsized };
+ (use) => { $crate::token::Use };
+ (virtual) => { $crate::token::Virtual };
+ (where) => { $crate::token::Where };
+ (while) => { $crate::token::While };
+ (yield) => { $crate::token::Yield };
+ (+) => { $crate::token::Add };
+ (+=) => { $crate::token::AddEq };
+ (&) => { $crate::token::And };
+ (&&) => { $crate::token::AndAnd };
+ (&=) => { $crate::token::AndEq };
+ (@) => { $crate::token::At };
+ (!) => { $crate::token::Bang };
+ (^) => { $crate::token::Caret };
+ (^=) => { $crate::token::CaretEq };
+ (:) => { $crate::token::Colon };
+ (::) => { $crate::token::Colon2 };
+ (,) => { $crate::token::Comma };
+ (/) => { $crate::token::Div };
+ (/=) => { $crate::token::DivEq };
+ ($) => { $crate::token::Dollar };
+ (.) => { $crate::token::Dot };
+ (..) => { $crate::token::Dot2 };
+ (...) => { $crate::token::Dot3 };
+ (..=) => { $crate::token::DotDotEq };
+ (=) => { $crate::token::Eq };
+ (==) => { $crate::token::EqEq };
+ (>=) => { $crate::token::Ge };
+ (>) => { $crate::token::Gt };
+ (<=) => { $crate::token::Le };
+ (<) => { $crate::token::Lt };
+ (*=) => { $crate::token::MulEq };
+ (!=) => { $crate::token::Ne };
+ (|) => { $crate::token::Or };
+ (|=) => { $crate::token::OrEq };
+ (||) => { $crate::token::OrOr };
+ (#) => { $crate::token::Pound };
+ (?) => { $crate::token::Question };
+ (->) => { $crate::token::RArrow };
+ (<-) => { $crate::token::LArrow };
+ (%) => { $crate::token::Rem };
+ (%=) => { $crate::token::RemEq };
+ (=>) => { $crate::token::FatArrow };
+ (;) => { $crate::token::Semi };
+ (<<) => { $crate::token::Shl };
+ (<<=) => { $crate::token::ShlEq };
+ (>>) => { $crate::token::Shr };
+ (>>=) => { $crate::token::ShrEq };
+ (*) => { $crate::token::Star };
+ (-) => { $crate::token::Sub };
+ (-=) => { $crate::token::SubEq };
+ (~) => { $crate::token::Tilde };
+ (_) => { $crate::token::Underscore };
+ }
+ };
+}
+
+// Old rustc does not permit `await` appearing anywhere in the source file.
+// https://github.com/rust-lang/rust/issues/57919
+// We put the Token![await] rule in a place that is not lexed by old rustc.
+#[cfg(not(syn_omit_await_from_token_macro))]
+include!("await.rs"); // export_token_macro![(await)];
+#[cfg(syn_omit_await_from_token_macro)]
+export_token_macro![];
+
+// Not public API.
+#[doc(hidden)]
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use proc_macro2::{Spacing, Span};
+
+ use crate::buffer::Cursor;
+ use crate::error::{Error, Result};
+ use crate::parse::ParseStream;
+ use crate::span::FromSpans;
+
+ pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
+ input.step(|cursor| {
+ if let Some((ident, rest)) = cursor.ident() {
+ if ident == token {
+ return Ok((ident.span(), rest));
+ }
+ }
+ Err(cursor.error(format!("expected `{}`", token)))
+ })
+ }
+
+ pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
+ if let Some((ident, _rest)) = cursor.ident() {
+ ident == token
+ } else {
+ false
+ }
+ }
+
+ pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
+ let mut spans = [input.span(); 3];
+ punct_helper(input, token, &mut spans)?;
+ Ok(S::from_spans(&spans))
+ }
+
+ fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
+ input.step(|cursor| {
+ let mut cursor = *cursor;
+ assert!(token.len() <= spans.len());
+
+ for (i, ch) in token.chars().enumerate() {
+ match cursor.punct() {
+ Some((punct, rest)) => {
+ spans[i] = punct.span();
+ if punct.as_char() != ch {
+ break;
+ } else if i == token.len() - 1 {
+ return Ok(((), rest));
+ } else if punct.spacing() != Spacing::Joint {
+ break;
+ }
+ cursor = rest;
+ }
+ None => break,
+ }
+ }
+
+ Err(Error::new(spans[0], format!("expected `{}`", token)))
+ })
+ }
+
+ pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
+ for (i, ch) in token.chars().enumerate() {
+ match cursor.punct() {
+ Some((punct, rest)) => {
+ if punct.as_char() != ch {
+ break;
+ } else if i == token.len() - 1 {
+ return true;
+ } else if punct.spacing() != Spacing::Joint {
+ break;
+ }
+ cursor = rest;
+ }
+ None => break,
+ }
+ }
+ false
+ }
+}
+
+// Not public API.
+#[doc(hidden)]
+#[cfg(feature = "printing")]
+pub mod printing {
+ use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
+ use quote::TokenStreamExt;
+
+ pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
+ assert_eq!(s.len(), spans.len());
+
+ let mut chars = s.chars();
+ let mut spans = spans.iter();
+ let ch = chars.next_back().unwrap();
+ let span = spans.next_back().unwrap();
+ for (ch, span) in chars.zip(spans) {
+ let mut op = Punct::new(ch, Spacing::Joint);
+ op.set_span(*span);
+ tokens.append(op);
+ }
+
+ let mut op = Punct::new(ch, Spacing::Alone);
+ op.set_span(*span);
+ tokens.append(op);
+ }
+
+ pub fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
+ tokens.append(Ident::new(s, span));
+ }
+
+ pub fn delim<F>(s: &str, span: Span, tokens: &mut TokenStream, f: F)
+ where
+ F: FnOnce(&mut TokenStream),
+ {
+ let delim = match s {
+ "(" => Delimiter::Parenthesis,
+ "[" => Delimiter::Bracket,
+ "{" => Delimiter::Brace,
+ " " => Delimiter::None,
+ _ => panic!("unknown delimiter: {}", s),
+ };
+ let mut inner = TokenStream::new();
+ f(&mut inner);
+ let mut g = Group::new(delim, inner);
+ g.set_span(span);
+ tokens.append(g);
+ }
+}
diff --git a/syn/src/tt.rs b/syn/src/tt.rs
new file mode 100644
index 0000000..8dba062
--- /dev/null
+++ b/syn/src/tt.rs
@@ -0,0 +1,108 @@
+use std::hash::{Hash, Hasher};
+
+use proc_macro2::{Delimiter, TokenStream, TokenTree};
+
+pub struct TokenTreeHelper<'a>(pub &'a TokenTree);
+
+impl<'a> PartialEq for TokenTreeHelper<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ use proc_macro2::Spacing;
+
+ match (self.0, other.0) {
+ (TokenTree::Group(g1), TokenTree::Group(g2)) => {
+ match (g1.delimiter(), g2.delimiter()) {
+ (Delimiter::Parenthesis, Delimiter::Parenthesis)
+ | (Delimiter::Brace, Delimiter::Brace)
+ | (Delimiter::Bracket, Delimiter::Bracket)
+ | (Delimiter::None, Delimiter::None) => {}
+ _ => return false,
+ }
+
+ let s1 = g1.stream().into_iter();
+ let mut s2 = g2.stream().into_iter();
+
+ for item1 in s1 {
+ let item2 = match s2.next() {
+ Some(item) => item,
+ None => return false,
+ };
+ if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) {
+ return false;
+ }
+ }
+ s2.next().is_none()
+ }
+ (TokenTree::Punct(o1), TokenTree::Punct(o2)) => {
+ o1.as_char() == o2.as_char()
+ && match (o1.spacing(), o2.spacing()) {
+ (Spacing::Alone, Spacing::Alone) | (Spacing::Joint, Spacing::Joint) => true,
+ _ => false,
+ }
+ }
+ (TokenTree::Literal(l1), TokenTree::Literal(l2)) => l1.to_string() == l2.to_string(),
+ (TokenTree::Ident(s1), TokenTree::Ident(s2)) => s1 == s2,
+ _ => false,
+ }
+ }
+}
+
+impl<'a> Hash for TokenTreeHelper<'a> {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ use proc_macro2::Spacing;
+
+ match self.0 {
+ TokenTree::Group(g) => {
+ 0u8.hash(h);
+ match g.delimiter() {
+ Delimiter::Parenthesis => 0u8.hash(h),
+ Delimiter::Brace => 1u8.hash(h),
+ Delimiter::Bracket => 2u8.hash(h),
+ Delimiter::None => 3u8.hash(h),
+ }
+
+ for item in g.stream() {
+ TokenTreeHelper(&item).hash(h);
+ }
+ 0xffu8.hash(h); // terminator w/ a variant we don't normally hash
+ }
+ TokenTree::Punct(op) => {
+ 1u8.hash(h);
+ op.as_char().hash(h);
+ match op.spacing() {
+ Spacing::Alone => 0u8.hash(h),
+ Spacing::Joint => 1u8.hash(h),
+ }
+ }
+ TokenTree::Literal(lit) => (2u8, lit.to_string()).hash(h),
+ TokenTree::Ident(word) => (3u8, word).hash(h),
+ }
+ }
+}
+
+pub struct TokenStreamHelper<'a>(pub &'a TokenStream);
+
+impl<'a> PartialEq for TokenStreamHelper<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ let left = self.0.clone().into_iter().collect::<Vec<_>>();
+ let right = other.0.clone().into_iter().collect::<Vec<_>>();
+ if left.len() != right.len() {
+ return false;
+ }
+ for (a, b) in left.into_iter().zip(right) {
+ if TokenTreeHelper(&a) != TokenTreeHelper(&b) {
+ return false;
+ }
+ }
+ true
+ }
+}
+
+impl<'a> Hash for TokenStreamHelper<'a> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let tts = self.0.clone().into_iter().collect::<Vec<_>>();
+ tts.len().hash(state);
+ for tt in tts {
+ TokenTreeHelper(&tt).hash(state);
+ }
+ }
+}
diff --git a/syn/src/ty.rs b/syn/src/ty.rs
new file mode 100644
index 0000000..b2e086b
--- /dev/null
+++ b/syn/src/ty.rs
@@ -0,0 +1,1178 @@
+use super::*;
+use crate::punctuated::Punctuated;
+#[cfg(feature = "extra-traits")]
+use crate::tt::TokenStreamHelper;
+use proc_macro2::TokenStream;
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+
+ast_enum_of_structs! {
+ /// The possible types that a Rust value could have.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ //
+ // TODO: change syntax-tree-enum link to an intra rustdoc link, currently
+ // blocked on https://github.com/rust-lang/rust/issues/62833
+ pub enum Type #manual_extra_traits {
+ /// A fixed size array type: `[T; n]`.
+ Array(TypeArray),
+
+ /// A bare function type: `fn(usize) -> bool`.
+ BareFn(TypeBareFn),
+
+ /// A type contained within invisible delimiters.
+ Group(TypeGroup),
+
+ /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or
+ /// a lifetime.
+ ImplTrait(TypeImplTrait),
+
+ /// Indication that a type should be inferred by the compiler: `_`.
+ Infer(TypeInfer),
+
+ /// A macro in the type position.
+ Macro(TypeMacro),
+
+ /// The never type: `!`.
+ Never(TypeNever),
+
+ /// A parenthesized type equivalent to the inner type.
+ Paren(TypeParen),
+
+ /// A path like `std::slice::Iter`, optionally qualified with a
+ /// self-type as in `<Vec<T> as SomeTrait>::Associated`.
+ Path(TypePath),
+
+ /// A raw pointer type: `*const T` or `*mut T`.
+ Ptr(TypePtr),
+
+ /// A reference type: `&'a T` or `&'a mut T`.
+ Reference(TypeReference),
+
+ /// A dynamically sized slice type: `[T]`.
+ Slice(TypeSlice),
+
+ /// A trait object type `Bound1 + Bound2 + Bound3` where `Bound` is a
+ /// trait or a lifetime.
+ TraitObject(TypeTraitObject),
+
+ /// A tuple type: `(A, B, C, String)`.
+ Tuple(TypeTuple),
+
+ /// Tokens in type position not interpreted by Syn.
+ Verbatim(TokenStream),
+
+ #[doc(hidden)]
+ __Nonexhaustive,
+ }
+}
+
+ast_struct! {
+ /// A fixed size array type: `[T; n]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeArray {
+ pub bracket_token: token::Bracket,
+ pub elem: Box<Type>,
+ pub semi_token: Token![;],
+ pub len: Expr,
+ }
+}
+
+ast_struct! {
+ /// A bare function type: `fn(usize) -> bool`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeBareFn {
+ pub lifetimes: Option<BoundLifetimes>,
+ pub unsafety: Option<Token![unsafe]>,
+ pub abi: Option<Abi>,
+ pub fn_token: Token![fn],
+ pub paren_token: token::Paren,
+ pub inputs: Punctuated<BareFnArg, Token![,]>,
+ pub variadic: Option<Variadic>,
+ pub output: ReturnType,
+ }
+}
+
+ast_struct! {
+ /// A type contained within invisible delimiters.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeGroup {
+ pub group_token: token::Group,
+ pub elem: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or
+ /// a lifetime.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeImplTrait {
+ pub impl_token: Token![impl],
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ }
+}
+
+ast_struct! {
+ /// Indication that a type should be inferred by the compiler: `_`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeInfer {
+ pub underscore_token: Token![_],
+ }
+}
+
+ast_struct! {
+ /// A macro in the type position.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeMacro {
+ pub mac: Macro,
+ }
+}
+
+ast_struct! {
+ /// The never type: `!`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeNever {
+ pub bang_token: Token![!],
+ }
+}
+
+ast_struct! {
+ /// A parenthesized type equivalent to the inner type.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeParen {
+ pub paren_token: token::Paren,
+ pub elem: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A path like `std::slice::Iter`, optionally qualified with a
+ /// self-type as in `<Vec<T> as SomeTrait>::Associated`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypePath {
+ pub qself: Option<QSelf>,
+ pub path: Path,
+ }
+}
+
+ast_struct! {
+ /// A raw pointer type: `*const T` or `*mut T`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypePtr {
+ pub star_token: Token![*],
+ pub const_token: Option<Token![const]>,
+ pub mutability: Option<Token![mut]>,
+ pub elem: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A reference type: `&'a T` or `&'a mut T`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeReference {
+ pub and_token: Token![&],
+ pub lifetime: Option<Lifetime>,
+ pub mutability: Option<Token![mut]>,
+ pub elem: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A dynamically sized slice type: `[T]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeSlice {
+ pub bracket_token: token::Bracket,
+ pub elem: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// A trait object type `Bound1 + Bound2 + Bound3` where `Bound` is a
+ /// trait or a lifetime.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeTraitObject {
+ pub dyn_token: Option<Token![dyn]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ }
+}
+
+ast_struct! {
+ /// A tuple type: `(A, B, C, String)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub struct TypeTuple {
+ pub paren_token: token::Paren,
+ pub elems: Punctuated<Type, Token![,]>,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Type {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Type::Array(this), Type::Array(other)) => this == other,
+ (Type::BareFn(this), Type::BareFn(other)) => this == other,
+ (Type::Group(this), Type::Group(other)) => this == other,
+ (Type::ImplTrait(this), Type::ImplTrait(other)) => this == other,
+ (Type::Infer(this), Type::Infer(other)) => this == other,
+ (Type::Macro(this), Type::Macro(other)) => this == other,
+ (Type::Never(this), Type::Never(other)) => this == other,
+ (Type::Paren(this), Type::Paren(other)) => this == other,
+ (Type::Path(this), Type::Path(other)) => this == other,
+ (Type::Ptr(this), Type::Ptr(other)) => this == other,
+ (Type::Reference(this), Type::Reference(other)) => this == other,
+ (Type::Slice(this), Type::Slice(other)) => this == other,
+ (Type::TraitObject(this), Type::TraitObject(other)) => this == other,
+ (Type::Tuple(this), Type::Tuple(other)) => this == other,
+ (Type::Verbatim(this), Type::Verbatim(other)) => {
+ TokenStreamHelper(this) == TokenStreamHelper(other)
+ }
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Type {
+ fn hash<H>(&self, hash: &mut H)
+ where
+ H: Hasher,
+ {
+ match self {
+ Type::Array(ty) => {
+ hash.write_u8(0);
+ ty.hash(hash);
+ }
+ Type::BareFn(ty) => {
+ hash.write_u8(1);
+ ty.hash(hash);
+ }
+ Type::Group(ty) => {
+ hash.write_u8(2);
+ ty.hash(hash);
+ }
+ Type::ImplTrait(ty) => {
+ hash.write_u8(3);
+ ty.hash(hash);
+ }
+ Type::Infer(ty) => {
+ hash.write_u8(4);
+ ty.hash(hash);
+ }
+ Type::Macro(ty) => {
+ hash.write_u8(5);
+ ty.hash(hash);
+ }
+ Type::Never(ty) => {
+ hash.write_u8(6);
+ ty.hash(hash);
+ }
+ Type::Paren(ty) => {
+ hash.write_u8(7);
+ ty.hash(hash);
+ }
+ Type::Path(ty) => {
+ hash.write_u8(8);
+ ty.hash(hash);
+ }
+ Type::Ptr(ty) => {
+ hash.write_u8(9);
+ ty.hash(hash);
+ }
+ Type::Reference(ty) => {
+ hash.write_u8(10);
+ ty.hash(hash);
+ }
+ Type::Slice(ty) => {
+ hash.write_u8(11);
+ ty.hash(hash);
+ }
+ Type::TraitObject(ty) => {
+ hash.write_u8(12);
+ ty.hash(hash);
+ }
+ Type::Tuple(ty) => {
+ hash.write_u8(13);
+ ty.hash(hash);
+ }
+ Type::Verbatim(ty) => {
+ hash.write_u8(14);
+ TokenStreamHelper(ty).hash(hash);
+ }
+ Type::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+
+ast_struct! {
+ /// The binary interface of a function: `extern "C"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Abi {
+ pub extern_token: Token![extern],
+ pub name: Option<LitStr>,
+ }
+}
+
+ast_struct! {
+ /// An argument in a function type: the `usize` in `fn(usize) -> bool`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct BareFnArg {
+ pub attrs: Vec<Attribute>,
+ pub name: Option<(Ident, Token![:])>,
+ pub ty: Type,
+ }
+}
+
+ast_struct! {
+ /// The variadic argument of a foreign function.
+ ///
+ /// ```rust
+ /// # struct c_char;
+ /// # struct c_int;
+ /// #
+ /// extern "C" {
+ /// fn printf(format: *const c_char, ...) -> c_int;
+ /// // ^^^
+ /// }
+ /// ```
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Variadic {
+ pub attrs: Vec<Attribute>,
+ pub dots: Token![...],
+ }
+}
+
+ast_enum! {
+ /// Return type of a function signature.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum ReturnType {
+ /// Return type is not specified.
+ ///
+ /// Functions default to `()` and closures default to type inference.
+ Default,
+ /// A particular type is returned.
+ Type(Token![->], Box<Type>),
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use crate::ext::IdentExt;
+ use crate::parse::{Parse, ParseStream, Result};
+ use crate::path;
+ use proc_macro2::{Punct, Spacing, TokenTree};
+ use std::iter::FromIterator;
+
+ impl Parse for Type {
+ fn parse(input: ParseStream) -> Result<Self> {
+ ambig_ty(input, true)
+ }
+ }
+
+ impl Type {
+ /// In some positions, types may not contain the `+` character, to
+ /// disambiguate them. For example in the expression `1 as T`, T may not
+ /// contain a `+` character.
+ ///
+ /// This parser does not allow a `+`, while the default parser does.
+ pub fn without_plus(input: ParseStream) -> Result<Self> {
+ ambig_ty(input, false)
+ }
+ }
+
+ fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result<Type> {
+ if input.peek(token::Group) {
+ return input.parse().map(Type::Group);
+ }
+
+ let mut lifetimes = None::<BoundLifetimes>;
+ let mut lookahead = input.lookahead1();
+ if lookahead.peek(Token![for]) {
+ lifetimes = input.parse()?;
+ lookahead = input.lookahead1();
+ if !lookahead.peek(Ident)
+ && !lookahead.peek(Token![fn])
+ && !lookahead.peek(Token![unsafe])
+ && !lookahead.peek(Token![extern])
+ && !lookahead.peek(Token![super])
+ && !lookahead.peek(Token![self])
+ && !lookahead.peek(Token![Self])
+ && !lookahead.peek(Token![crate])
+ {
+ return Err(lookahead.error());
+ }
+ }
+
+ if lookahead.peek(token::Paren) {
+ let content;
+ let paren_token = parenthesized!(content in input);
+ if content.is_empty() {
+ return Ok(Type::Tuple(TypeTuple {
+ paren_token,
+ elems: Punctuated::new(),
+ }));
+ }
+ if content.peek(Lifetime) {
+ return Ok(Type::Paren(TypeParen {
+ paren_token,
+ elem: Box::new(Type::TraitObject(content.parse()?)),
+ }));
+ }
+ if content.peek(Token![?]) {
+ return Ok(Type::TraitObject(TypeTraitObject {
+ dyn_token: None,
+ bounds: {
+ let mut bounds = Punctuated::new();
+ bounds.push_value(TypeParamBound::Trait(TraitBound {
+ paren_token: Some(paren_token),
+ ..content.parse()?
+ }));
+ while let Some(plus) = input.parse()? {
+ bounds.push_punct(plus);
+ bounds.push_value(input.parse()?);
+ }
+ bounds
+ },
+ }));
+ }
+ let mut first: Type = content.parse()?;
+ if content.peek(Token![,]) {
+ return Ok(Type::Tuple(TypeTuple {
+ paren_token,
+ elems: {
+ let mut elems = Punctuated::new();
+ elems.push_value(first);
+ elems.push_punct(content.parse()?);
+ let rest: Punctuated<Type, Token![,]> =
+ content.parse_terminated(Parse::parse)?;
+ elems.extend(rest);
+ elems
+ },
+ }));
+ }
+ if allow_plus && input.peek(Token![+]) {
+ loop {
+ let first = match first {
+ Type::Path(TypePath { qself: None, path }) => {
+ TypeParamBound::Trait(TraitBound {
+ paren_token: Some(paren_token),
+ modifier: TraitBoundModifier::None,
+ lifetimes: None,
+ path,
+ })
+ }
+ Type::TraitObject(TypeTraitObject {
+ dyn_token: None,
+ bounds,
+ }) => {
+ if bounds.len() > 1 || bounds.trailing_punct() {
+ first = Type::TraitObject(TypeTraitObject {
+ dyn_token: None,
+ bounds,
+ });
+ break;
+ }
+ match bounds.into_iter().next().unwrap() {
+ TypeParamBound::Trait(trait_bound) => {
+ TypeParamBound::Trait(TraitBound {
+ paren_token: Some(paren_token),
+ ..trait_bound
+ })
+ }
+ other => other,
+ }
+ }
+ _ => break,
+ };
+ return Ok(Type::TraitObject(TypeTraitObject {
+ dyn_token: None,
+ bounds: {
+ let mut bounds = Punctuated::new();
+ bounds.push_value(first);
+ while let Some(plus) = input.parse()? {
+ bounds.push_punct(plus);
+ bounds.push_value(input.parse()?);
+ }
+ bounds
+ },
+ }));
+ }
+ }
+ Ok(Type::Paren(TypeParen {
+ paren_token,
+ elem: Box::new(first),
+ }))
+ } else if lookahead.peek(Token![fn])
+ || lookahead.peek(Token![unsafe])
+ || lookahead.peek(Token![extern]) && !input.peek2(Token![::])
+ {
+ let mut bare_fn: TypeBareFn = input.parse()?;
+ bare_fn.lifetimes = lifetimes;
+ Ok(Type::BareFn(bare_fn))
+ } else if lookahead.peek(Ident)
+ || input.peek(Token![super])
+ || input.peek(Token![self])
+ || input.peek(Token![Self])
+ || input.peek(Token![crate])
+ || input.peek(Token![extern])
+ || lookahead.peek(Token![::])
+ || lookahead.peek(Token![<])
+ {
+ if input.peek(Token![dyn]) {
+ let mut trait_object: TypeTraitObject = input.parse()?;
+ if lifetimes.is_some() {
+ match trait_object.bounds.iter_mut().next().unwrap() {
+ TypeParamBound::Trait(trait_bound) => {
+ trait_bound.lifetimes = lifetimes;
+ }
+ TypeParamBound::Lifetime(_) => unreachable!(),
+ }
+ }
+ return Ok(Type::TraitObject(trait_object));
+ }
+
+ let ty: TypePath = input.parse()?;
+ if ty.qself.is_some() {
+ return Ok(Type::Path(ty));
+ }
+
+ if input.peek(Token![!]) && !input.peek(Token![!=]) {
+ let mut contains_arguments = false;
+ for segment in &ty.path.segments {
+ match segment.arguments {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => {
+ contains_arguments = true;
+ }
+ }
+ }
+
+ if !contains_arguments {
+ let bang_token: Token![!] = input.parse()?;
+ let (delimiter, tokens) = mac::parse_delimiter(input)?;
+ return Ok(Type::Macro(TypeMacro {
+ mac: Macro {
+ path: ty.path,
+ bang_token,
+ delimiter,
+ tokens,
+ },
+ }));
+ }
+ }
+
+ if lifetimes.is_some() || allow_plus && input.peek(Token![+]) {
+ let mut bounds = Punctuated::new();
+ bounds.push_value(TypeParamBound::Trait(TraitBound {
+ paren_token: None,
+ modifier: TraitBoundModifier::None,
+ lifetimes,
+ path: ty.path,
+ }));
+ if allow_plus {
+ while input.peek(Token![+]) {
+ bounds.push_punct(input.parse()?);
+ if input.peek(Token![>]) {
+ break;
+ }
+ bounds.push_value(input.parse()?);
+ }
+ }
+ return Ok(Type::TraitObject(TypeTraitObject {
+ dyn_token: None,
+ bounds,
+ }));
+ }
+
+ Ok(Type::Path(ty))
+ } else if lookahead.peek(token::Bracket) {
+ let content;
+ let bracket_token = bracketed!(content in input);
+ let elem: Type = content.parse()?;
+ if content.peek(Token![;]) {
+ Ok(Type::Array(TypeArray {
+ bracket_token,
+ elem: Box::new(elem),
+ semi_token: content.parse()?,
+ len: content.parse()?,
+ }))
+ } else {
+ Ok(Type::Slice(TypeSlice {
+ bracket_token,
+ elem: Box::new(elem),
+ }))
+ }
+ } else if lookahead.peek(Token![*]) {
+ input.parse().map(Type::Ptr)
+ } else if lookahead.peek(Token![&]) {
+ input.parse().map(Type::Reference)
+ } else if lookahead.peek(Token![!]) && !input.peek(Token![=]) {
+ input.parse().map(Type::Never)
+ } else if lookahead.peek(Token![impl]) {
+ input.parse().map(Type::ImplTrait)
+ } else if lookahead.peek(Token![_]) {
+ input.parse().map(Type::Infer)
+ } else if lookahead.peek(Lifetime) {
+ input.parse().map(Type::TraitObject)
+ } else {
+ Err(lookahead.error())
+ }
+ }
+
+ impl Parse for TypeSlice {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(TypeSlice {
+ bracket_token: bracketed!(content in input),
+ elem: content.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TypeArray {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ Ok(TypeArray {
+ bracket_token: bracketed!(content in input),
+ elem: content.parse()?,
+ semi_token: content.parse()?,
+ len: content.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TypePtr {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let star_token: Token![*] = input.parse()?;
+
+ let lookahead = input.lookahead1();
+ let (const_token, mutability) = if lookahead.peek(Token![const]) {
+ (Some(input.parse()?), None)
+ } else if lookahead.peek(Token![mut]) {
+ (None, Some(input.parse()?))
+ } else {
+ return Err(lookahead.error());
+ };
+
+ Ok(TypePtr {
+ star_token,
+ const_token,
+ mutability,
+ elem: Box::new(input.call(Type::without_plus)?),
+ })
+ }
+ }
+
+ impl Parse for TypeReference {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeReference {
+ and_token: input.parse()?,
+ lifetime: input.parse()?,
+ mutability: input.parse()?,
+ // & binds tighter than +, so we don't allow + here.
+ elem: Box::new(input.call(Type::without_plus)?),
+ })
+ }
+ }
+
+ impl Parse for TypeBareFn {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let args;
+ let mut variadic = None;
+ Ok(TypeBareFn {
+ lifetimes: input.parse()?,
+ unsafety: input.parse()?,
+ abi: input.parse()?,
+ fn_token: input.parse()?,
+ paren_token: parenthesized!(args in input),
+ inputs: {
+ let mut inputs = Punctuated::new();
+
+ while !args.is_empty() {
+ let attrs = args.call(Attribute::parse_outer)?;
+
+ if inputs.empty_or_trailing() && args.peek(Token![...]) {
+ variadic = Some(Variadic {
+ attrs,
+ dots: args.parse()?,
+ });
+ break;
+ }
+
+ inputs.push_value(BareFnArg {
+ attrs,
+ ..args.parse()?
+ });
+ if args.is_empty() {
+ break;
+ }
+
+ inputs.push_punct(args.parse()?);
+ }
+
+ inputs
+ },
+ variadic,
+ output: input.call(ReturnType::without_plus)?,
+ })
+ }
+ }
+
+ impl Parse for TypeNever {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeNever {
+ bang_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TypeInfer {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeInfer {
+ underscore_token: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TypeTuple {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ let paren_token = parenthesized!(content in input);
+
+ if content.is_empty() {
+ return Ok(TypeTuple {
+ paren_token,
+ elems: Punctuated::new(),
+ });
+ }
+
+ let first: Type = content.parse()?;
+ Ok(TypeTuple {
+ paren_token,
+ elems: {
+ let mut elems = Punctuated::new();
+ elems.push_value(first);
+ elems.push_punct(content.parse()?);
+ let rest: Punctuated<Type, Token![,]> =
+ content.parse_terminated(Parse::parse)?;
+ elems.extend(rest);
+ elems
+ },
+ })
+ }
+ }
+
+ impl Parse for TypeMacro {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeMacro {
+ mac: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TypePath {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let (qself, mut path) = path::parsing::qpath(input, false)?;
+
+ if path.segments.last().unwrap().arguments.is_empty() && input.peek(token::Paren) {
+ let args: ParenthesizedGenericArguments = input.parse()?;
+ let parenthesized = PathArguments::Parenthesized(args);
+ path.segments.last_mut().unwrap().arguments = parenthesized;
+ }
+
+ Ok(TypePath { qself, path })
+ }
+ }
+
+ impl ReturnType {
+ pub fn without_plus(input: ParseStream) -> Result<Self> {
+ Self::parse(input, false)
+ }
+
+ pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
+ if input.peek(Token![->]) {
+ let arrow = input.parse()?;
+ let ty = ambig_ty(input, allow_plus)?;
+ Ok(ReturnType::Type(arrow, Box::new(ty)))
+ } else {
+ Ok(ReturnType::Default)
+ }
+ }
+ }
+
+ impl Parse for ReturnType {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse(input, true)
+ }
+ }
+
+ impl Parse for TypeTraitObject {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse(input, true)
+ }
+ }
+
+ fn at_least_one_type(bounds: &Punctuated<TypeParamBound, Token![+]>) -> bool {
+ for bound in bounds {
+ if let TypeParamBound::Trait(_) = *bound {
+ return true;
+ }
+ }
+ false
+ }
+
+ impl TypeTraitObject {
+ pub fn without_plus(input: ParseStream) -> Result<Self> {
+ Self::parse(input, false)
+ }
+
+ // Only allow multiple trait references if allow_plus is true.
+ pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
+ Ok(TypeTraitObject {
+ dyn_token: input.parse()?,
+ bounds: {
+ let mut bounds = Punctuated::new();
+ if allow_plus {
+ loop {
+ bounds.push_value(input.parse()?);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ bounds.push_punct(input.parse()?);
+ if input.peek(Token![>]) {
+ break;
+ }
+ }
+ } else {
+ bounds.push_value(input.parse()?);
+ }
+ // Just lifetimes like `'a + 'b` is not a TraitObject.
+ if !at_least_one_type(&bounds) {
+ return Err(input.error("expected at least one type"));
+ }
+ bounds
+ },
+ })
+ }
+ }
+
+ impl Parse for TypeImplTrait {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(TypeImplTrait {
+ impl_token: input.parse()?,
+ // NOTE: rust-lang/rust#34511 includes discussion about whether
+ // or not + should be allowed in ImplTrait directly without ().
+ bounds: {
+ let mut bounds = Punctuated::new();
+ loop {
+ bounds.push_value(input.parse()?);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ bounds.push_punct(input.parse()?);
+ }
+ bounds
+ },
+ })
+ }
+ }
+
+ impl Parse for TypeGroup {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let group = crate::group::parse_group(input)?;
+ Ok(TypeGroup {
+ group_token: group.token,
+ elem: group.content.parse()?,
+ })
+ }
+ }
+
+ impl Parse for TypeParen {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Self::parse(input, false)
+ }
+ }
+
+ impl TypeParen {
+ fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
+ let content;
+ Ok(TypeParen {
+ paren_token: parenthesized!(content in input),
+ elem: Box::new(ambig_ty(&content, allow_plus)?),
+ })
+ }
+ }
+
+ impl Parse for BareFnArg {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(BareFnArg {
+ attrs: input.call(Attribute::parse_outer)?,
+ name: {
+ if (input.peek(Ident) || input.peek(Token![_]))
+ && input.peek2(Token![:])
+ && !input.peek2(Token![::])
+ {
+ let name = input.call(Ident::parse_any)?;
+ let colon: Token![:] = input.parse()?;
+ Some((name, colon))
+ } else {
+ None
+ }
+ },
+ ty: match input.parse::<Option<Token![...]>>()? {
+ Some(dot3) => {
+ let args = vec![
+ TokenTree::Punct(Punct::new('.', Spacing::Joint)),
+ TokenTree::Punct(Punct::new('.', Spacing::Joint)),
+ TokenTree::Punct(Punct::new('.', Spacing::Alone)),
+ ];
+ let tokens = TokenStream::from_iter(args.into_iter().zip(&dot3.spans).map(
+ |(mut arg, span)| {
+ arg.set_span(*span);
+ arg
+ },
+ ));
+ Type::Verbatim(tokens)
+ }
+ None => input.parse()?,
+ },
+ })
+ }
+ }
+
+ impl Parse for Abi {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Abi {
+ extern_token: input.parse()?,
+ name: input.parse()?,
+ })
+ }
+ }
+
+ impl Parse for Option<Abi> {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.peek(Token![extern]) {
+ input.parse().map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ use crate::attr::FilterAttrs;
+ use crate::print::TokensOrDefault;
+
+ impl ToTokens for TypeSlice {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.bracket_token.surround(tokens, |tokens| {
+ self.elem.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypeArray {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.bracket_token.surround(tokens, |tokens| {
+ self.elem.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ self.len.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypePtr {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.star_token.to_tokens(tokens);
+ match &self.mutability {
+ Some(tok) => tok.to_tokens(tokens),
+ None => {
+ TokensOrDefault(&self.const_token).to_tokens(tokens);
+ }
+ }
+ self.elem.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeReference {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.and_token.to_tokens(tokens);
+ self.lifetime.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.elem.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeBareFn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lifetimes.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.abi.to_tokens(tokens);
+ self.fn_token.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.inputs.to_tokens(tokens);
+ if let Some(variadic) = &self.variadic {
+ if !self.inputs.empty_or_trailing() {
+ let span = variadic.dots.spans[0];
+ Token![,](span).to_tokens(tokens);
+ }
+ variadic.to_tokens(tokens);
+ }
+ });
+ self.output.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeNever {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.bang_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.elems.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypePath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ private::print_path(tokens, &self.qself, &self.path);
+ }
+ }
+
+ impl ToTokens for TypeTraitObject {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.dyn_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeImplTrait {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.impl_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeGroup {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.group_token.surround(tokens, |tokens| {
+ self.elem.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypeParen {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.elem.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypeInfer {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.underscore_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.mac.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ReturnType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ ReturnType::Default => {}
+ ReturnType::Type(arrow, ty) => {
+ arrow.to_tokens(tokens);
+ ty.to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for BareFnArg {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ if let Some((name, colon)) = &self.name {
+ name.to_tokens(tokens);
+ colon.to_tokens(tokens);
+ }
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Variadic {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.dots.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Abi {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.extern_token.to_tokens(tokens);
+ self.name.to_tokens(tokens);
+ }
+ }
+}
diff --git a/syn/syn.json b/syn/syn.json
new file mode 100644
index 0000000..c600700
--- /dev/null
+++ b/syn/syn.json
@@ -0,0 +1,5616 @@
+{
+ "version": "1.0.12",
+ "types": [
+ {
+ "ident": "Abi",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "extern_token": {
+ "token": "Extern"
+ },
+ "name": {
+ "option": {
+ "syn": "LitStr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "AngleBracketedGenericArguments",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "colon2_token": {
+ "option": {
+ "token": "Colon2"
+ }
+ },
+ "lt_token": {
+ "token": "Lt"
+ },
+ "args": {
+ "punctuated": {
+ "element": {
+ "syn": "GenericArgument"
+ },
+ "punct": "Comma"
+ }
+ },
+ "gt_token": {
+ "token": "Gt"
+ }
+ }
+ },
+ {
+ "ident": "Arm",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "pat": {
+ "syn": "Pat"
+ },
+ "guard": {
+ "option": {
+ "tuple": [
+ {
+ "token": "If"
+ },
+ {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ ]
+ }
+ },
+ "fat_arrow_token": {
+ "token": "FatArrow"
+ },
+ "body": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "comma": {
+ "option": {
+ "token": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "AttrStyle",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Outer": [],
+ "Inner": [
+ {
+ "token": "Bang"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "Attribute",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "pound_token": {
+ "token": "Pound"
+ },
+ "style": {
+ "syn": "AttrStyle"
+ },
+ "bracket_token": {
+ "group": "Bracket"
+ },
+ "path": {
+ "syn": "Path"
+ },
+ "tokens": {
+ "proc_macro2": "TokenStream"
+ }
+ }
+ },
+ {
+ "ident": "BareFnArg",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "name": {
+ "option": {
+ "tuple": [
+ {
+ "proc_macro2": "Ident"
+ },
+ {
+ "token": "Colon"
+ }
+ ]
+ }
+ },
+ "ty": {
+ "syn": "Type"
+ }
+ }
+ },
+ {
+ "ident": "BinOp",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Add": [
+ {
+ "token": "Add"
+ }
+ ],
+ "Sub": [
+ {
+ "token": "Sub"
+ }
+ ],
+ "Mul": [
+ {
+ "token": "Star"
+ }
+ ],
+ "Div": [
+ {
+ "token": "Div"
+ }
+ ],
+ "Rem": [
+ {
+ "token": "Rem"
+ }
+ ],
+ "And": [
+ {
+ "token": "AndAnd"
+ }
+ ],
+ "Or": [
+ {
+ "token": "OrOr"
+ }
+ ],
+ "BitXor": [
+ {
+ "token": "Caret"
+ }
+ ],
+ "BitAnd": [
+ {
+ "token": "And"
+ }
+ ],
+ "BitOr": [
+ {
+ "token": "Or"
+ }
+ ],
+ "Shl": [
+ {
+ "token": "Shl"
+ }
+ ],
+ "Shr": [
+ {
+ "token": "Shr"
+ }
+ ],
+ "Eq": [
+ {
+ "token": "EqEq"
+ }
+ ],
+ "Lt": [
+ {
+ "token": "Lt"
+ }
+ ],
+ "Le": [
+ {
+ "token": "Le"
+ }
+ ],
+ "Ne": [
+ {
+ "token": "Ne"
+ }
+ ],
+ "Ge": [
+ {
+ "token": "Ge"
+ }
+ ],
+ "Gt": [
+ {
+ "token": "Gt"
+ }
+ ],
+ "AddEq": [
+ {
+ "token": "AddEq"
+ }
+ ],
+ "SubEq": [
+ {
+ "token": "SubEq"
+ }
+ ],
+ "MulEq": [
+ {
+ "token": "MulEq"
+ }
+ ],
+ "DivEq": [
+ {
+ "token": "DivEq"
+ }
+ ],
+ "RemEq": [
+ {
+ "token": "RemEq"
+ }
+ ],
+ "BitXorEq": [
+ {
+ "token": "CaretEq"
+ }
+ ],
+ "BitAndEq": [
+ {
+ "token": "AndEq"
+ }
+ ],
+ "BitOrEq": [
+ {
+ "token": "OrEq"
+ }
+ ],
+ "ShlEq": [
+ {
+ "token": "ShlEq"
+ }
+ ],
+ "ShrEq": [
+ {
+ "token": "ShrEq"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "Binding",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "ty": {
+ "syn": "Type"
+ }
+ }
+ },
+ {
+ "ident": "Block",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "brace_token": {
+ "group": "Brace"
+ },
+ "stmts": {
+ "vec": {
+ "syn": "Stmt"
+ }
+ }
+ }
+ },
+ {
+ "ident": "BoundLifetimes",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "for_token": {
+ "token": "For"
+ },
+ "lt_token": {
+ "token": "Lt"
+ },
+ "lifetimes": {
+ "punctuated": {
+ "element": {
+ "syn": "LifetimeDef"
+ },
+ "punct": "Comma"
+ }
+ },
+ "gt_token": {
+ "token": "Gt"
+ }
+ }
+ },
+ {
+ "ident": "ConstParam",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "const_token": {
+ "token": "Const"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "ty": {
+ "syn": "Type"
+ },
+ "eq_token": {
+ "option": {
+ "token": "Eq"
+ }
+ },
+ "default": {
+ "option": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "Constraint",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "TypeParamBound"
+ },
+ "punct": "Add"
+ }
+ }
+ }
+ },
+ {
+ "ident": "Data",
+ "features": {
+ "any": [
+ "derive"
+ ]
+ },
+ "variants": {
+ "Struct": [
+ {
+ "syn": "DataStruct"
+ }
+ ],
+ "Enum": [
+ {
+ "syn": "DataEnum"
+ }
+ ],
+ "Union": [
+ {
+ "syn": "DataUnion"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "DataEnum",
+ "features": {
+ "any": [
+ "derive"
+ ]
+ },
+ "fields": {
+ "enum_token": {
+ "token": "Enum"
+ },
+ "brace_token": {
+ "group": "Brace"
+ },
+ "variants": {
+ "punctuated": {
+ "element": {
+ "syn": "Variant"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "DataStruct",
+ "features": {
+ "any": [
+ "derive"
+ ]
+ },
+ "fields": {
+ "struct_token": {
+ "token": "Struct"
+ },
+ "fields": {
+ "syn": "Fields"
+ },
+ "semi_token": {
+ "option": {
+ "token": "Semi"
+ }
+ }
+ }
+ },
+ {
+ "ident": "DataUnion",
+ "features": {
+ "any": [
+ "derive"
+ ]
+ },
+ "fields": {
+ "union_token": {
+ "token": "Union"
+ },
+ "fields": {
+ "syn": "FieldsNamed"
+ }
+ }
+ },
+ {
+ "ident": "DeriveInput",
+ "features": {
+ "any": [
+ "derive"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "data": {
+ "syn": "Data"
+ }
+ }
+ },
+ {
+ "ident": "Expr",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Array": [
+ {
+ "syn": "ExprArray"
+ }
+ ],
+ "Assign": [
+ {
+ "syn": "ExprAssign"
+ }
+ ],
+ "AssignOp": [
+ {
+ "syn": "ExprAssignOp"
+ }
+ ],
+ "Async": [
+ {
+ "syn": "ExprAsync"
+ }
+ ],
+ "Await": [
+ {
+ "syn": "ExprAwait"
+ }
+ ],
+ "Binary": [
+ {
+ "syn": "ExprBinary"
+ }
+ ],
+ "Block": [
+ {
+ "syn": "ExprBlock"
+ }
+ ],
+ "Box": [
+ {
+ "syn": "ExprBox"
+ }
+ ],
+ "Break": [
+ {
+ "syn": "ExprBreak"
+ }
+ ],
+ "Call": [
+ {
+ "syn": "ExprCall"
+ }
+ ],
+ "Cast": [
+ {
+ "syn": "ExprCast"
+ }
+ ],
+ "Closure": [
+ {
+ "syn": "ExprClosure"
+ }
+ ],
+ "Continue": [
+ {
+ "syn": "ExprContinue"
+ }
+ ],
+ "Field": [
+ {
+ "syn": "ExprField"
+ }
+ ],
+ "ForLoop": [
+ {
+ "syn": "ExprForLoop"
+ }
+ ],
+ "Group": [
+ {
+ "syn": "ExprGroup"
+ }
+ ],
+ "If": [
+ {
+ "syn": "ExprIf"
+ }
+ ],
+ "Index": [
+ {
+ "syn": "ExprIndex"
+ }
+ ],
+ "Let": [
+ {
+ "syn": "ExprLet"
+ }
+ ],
+ "Lit": [
+ {
+ "syn": "ExprLit"
+ }
+ ],
+ "Loop": [
+ {
+ "syn": "ExprLoop"
+ }
+ ],
+ "Macro": [
+ {
+ "syn": "ExprMacro"
+ }
+ ],
+ "Match": [
+ {
+ "syn": "ExprMatch"
+ }
+ ],
+ "MethodCall": [
+ {
+ "syn": "ExprMethodCall"
+ }
+ ],
+ "Paren": [
+ {
+ "syn": "ExprParen"
+ }
+ ],
+ "Path": [
+ {
+ "syn": "ExprPath"
+ }
+ ],
+ "Range": [
+ {
+ "syn": "ExprRange"
+ }
+ ],
+ "Reference": [
+ {
+ "syn": "ExprReference"
+ }
+ ],
+ "Repeat": [
+ {
+ "syn": "ExprRepeat"
+ }
+ ],
+ "Return": [
+ {
+ "syn": "ExprReturn"
+ }
+ ],
+ "Struct": [
+ {
+ "syn": "ExprStruct"
+ }
+ ],
+ "Try": [
+ {
+ "syn": "ExprTry"
+ }
+ ],
+ "TryBlock": [
+ {
+ "syn": "ExprTryBlock"
+ }
+ ],
+ "Tuple": [
+ {
+ "syn": "ExprTuple"
+ }
+ ],
+ "Type": [
+ {
+ "syn": "ExprType"
+ }
+ ],
+ "Unary": [
+ {
+ "syn": "ExprUnary"
+ }
+ ],
+ "Unsafe": [
+ {
+ "syn": "ExprUnsafe"
+ }
+ ],
+ "Verbatim": [
+ {
+ "proc_macro2": "TokenStream"
+ }
+ ],
+ "While": [
+ {
+ "syn": "ExprWhile"
+ }
+ ],
+ "Yield": [
+ {
+ "syn": "ExprYield"
+ }
+ ]
+ },
+ "exhaustive": false
+ },
+ {
+ "ident": "ExprArray",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "bracket_token": {
+ "group": "Bracket"
+ },
+ "elems": {
+ "punctuated": {
+ "element": {
+ "syn": "Expr"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprAssign",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "left": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "right": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprAssignOp",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "left": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "op": {
+ "syn": "BinOp"
+ },
+ "right": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprAsync",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "async_token": {
+ "token": "Async"
+ },
+ "capture": {
+ "option": {
+ "token": "Move"
+ }
+ },
+ "block": {
+ "syn": "Block"
+ }
+ }
+ },
+ {
+ "ident": "ExprAwait",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "base": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "dot_token": {
+ "token": "Dot"
+ },
+ "await_token": {
+ "token": "Await"
+ }
+ }
+ },
+ {
+ "ident": "ExprBinary",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "left": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "op": {
+ "syn": "BinOp"
+ },
+ "right": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprBlock",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "label": {
+ "option": {
+ "syn": "Label"
+ }
+ },
+ "block": {
+ "syn": "Block"
+ }
+ }
+ },
+ {
+ "ident": "ExprBox",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "box_token": {
+ "token": "Box"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprBreak",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "break_token": {
+ "token": "Break"
+ },
+ "label": {
+ "option": {
+ "syn": "Lifetime"
+ }
+ },
+ "expr": {
+ "option": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprCall",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "func": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "args": {
+ "punctuated": {
+ "element": {
+ "syn": "Expr"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprCast",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "as_token": {
+ "token": "As"
+ },
+ "ty": {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprClosure",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "asyncness": {
+ "option": {
+ "token": "Async"
+ }
+ },
+ "movability": {
+ "option": {
+ "token": "Static"
+ }
+ },
+ "capture": {
+ "option": {
+ "token": "Move"
+ }
+ },
+ "or1_token": {
+ "token": "Or"
+ },
+ "inputs": {
+ "punctuated": {
+ "element": {
+ "syn": "Pat"
+ },
+ "punct": "Comma"
+ }
+ },
+ "or2_token": {
+ "token": "Or"
+ },
+ "output": {
+ "syn": "ReturnType"
+ },
+ "body": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprContinue",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "continue_token": {
+ "token": "Continue"
+ },
+ "label": {
+ "option": {
+ "syn": "Lifetime"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprField",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "base": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "dot_token": {
+ "token": "Dot"
+ },
+ "member": {
+ "syn": "Member"
+ }
+ }
+ },
+ {
+ "ident": "ExprForLoop",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "label": {
+ "option": {
+ "syn": "Label"
+ }
+ },
+ "for_token": {
+ "token": "For"
+ },
+ "pat": {
+ "syn": "Pat"
+ },
+ "in_token": {
+ "token": "In"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "body": {
+ "syn": "Block"
+ }
+ }
+ },
+ {
+ "ident": "ExprGroup",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "group_token": {
+ "group": "Group"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprIf",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "if_token": {
+ "token": "If"
+ },
+ "cond": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "then_branch": {
+ "syn": "Block"
+ },
+ "else_branch": {
+ "option": {
+ "tuple": [
+ {
+ "token": "Else"
+ },
+ {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprIndex",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "bracket_token": {
+ "group": "Bracket"
+ },
+ "index": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprLet",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "let_token": {
+ "token": "Let"
+ },
+ "pat": {
+ "syn": "Pat"
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprLit",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "lit": {
+ "syn": "Lit"
+ }
+ }
+ },
+ {
+ "ident": "ExprLoop",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "label": {
+ "option": {
+ "syn": "Label"
+ }
+ },
+ "loop_token": {
+ "token": "Loop"
+ },
+ "body": {
+ "syn": "Block"
+ }
+ }
+ },
+ {
+ "ident": "ExprMacro",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "mac": {
+ "syn": "Macro"
+ }
+ }
+ },
+ {
+ "ident": "ExprMatch",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "match_token": {
+ "token": "Match"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "brace_token": {
+ "group": "Brace"
+ },
+ "arms": {
+ "vec": {
+ "syn": "Arm"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprMethodCall",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "receiver": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "dot_token": {
+ "token": "Dot"
+ },
+ "method": {
+ "proc_macro2": "Ident"
+ },
+ "turbofish": {
+ "option": {
+ "syn": "MethodTurbofish"
+ }
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "args": {
+ "punctuated": {
+ "element": {
+ "syn": "Expr"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprParen",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprPath",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "qself": {
+ "option": {
+ "syn": "QSelf"
+ }
+ },
+ "path": {
+ "syn": "Path"
+ }
+ }
+ },
+ {
+ "ident": "ExprRange",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "from": {
+ "option": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ },
+ "limits": {
+ "syn": "RangeLimits"
+ },
+ "to": {
+ "option": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprReference",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "and_token": {
+ "token": "And"
+ },
+ "raw": {
+ "syn": "Reserved"
+ },
+ "mutability": {
+ "option": {
+ "token": "Mut"
+ }
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprRepeat",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "bracket_token": {
+ "group": "Bracket"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ },
+ "len": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprReturn",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "return_token": {
+ "token": "Return"
+ },
+ "expr": {
+ "option": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprStruct",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "path": {
+ "syn": "Path"
+ },
+ "brace_token": {
+ "group": "Brace"
+ },
+ "fields": {
+ "punctuated": {
+ "element": {
+ "syn": "FieldValue"
+ },
+ "punct": "Comma"
+ }
+ },
+ "dot2_token": {
+ "option": {
+ "token": "Dot2"
+ }
+ },
+ "rest": {
+ "option": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprTry",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "question_token": {
+ "token": "Question"
+ }
+ }
+ },
+ {
+ "ident": "ExprTryBlock",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "try_token": {
+ "token": "Try"
+ },
+ "block": {
+ "syn": "Block"
+ }
+ }
+ },
+ {
+ "ident": "ExprTuple",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "elems": {
+ "punctuated": {
+ "element": {
+ "syn": "Expr"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprType",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "ty": {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprUnary",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "op": {
+ "syn": "UnOp"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ExprUnsafe",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "unsafe_token": {
+ "token": "Unsafe"
+ },
+ "block": {
+ "syn": "Block"
+ }
+ }
+ },
+ {
+ "ident": "ExprWhile",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "label": {
+ "option": {
+ "syn": "Label"
+ }
+ },
+ "while_token": {
+ "token": "While"
+ },
+ "cond": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "body": {
+ "syn": "Block"
+ }
+ }
+ },
+ {
+ "ident": "ExprYield",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "yield_token": {
+ "token": "Yield"
+ },
+ "expr": {
+ "option": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ }
+ },
+ {
+ "ident": "Field",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "ident": {
+ "option": {
+ "proc_macro2": "Ident"
+ }
+ },
+ "colon_token": {
+ "option": {
+ "token": "Colon"
+ }
+ },
+ "ty": {
+ "syn": "Type"
+ }
+ }
+ },
+ {
+ "ident": "FieldPat",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "member": {
+ "syn": "Member"
+ },
+ "colon_token": {
+ "option": {
+ "token": "Colon"
+ }
+ },
+ "pat": {
+ "box": {
+ "syn": "Pat"
+ }
+ }
+ }
+ },
+ {
+ "ident": "FieldValue",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "member": {
+ "syn": "Member"
+ },
+ "colon_token": {
+ "option": {
+ "token": "Colon"
+ }
+ },
+ "expr": {
+ "syn": "Expr"
+ }
+ }
+ },
+ {
+ "ident": "Fields",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Named": [
+ {
+ "syn": "FieldsNamed"
+ }
+ ],
+ "Unnamed": [
+ {
+ "syn": "FieldsUnnamed"
+ }
+ ],
+ "Unit": []
+ }
+ },
+ {
+ "ident": "FieldsNamed",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "brace_token": {
+ "group": "Brace"
+ },
+ "named": {
+ "punctuated": {
+ "element": {
+ "syn": "Field"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "FieldsUnnamed",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "paren_token": {
+ "group": "Paren"
+ },
+ "unnamed": {
+ "punctuated": {
+ "element": {
+ "syn": "Field"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "File",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "shebang": {
+ "option": {
+ "std": "String"
+ }
+ },
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "items": {
+ "vec": {
+ "syn": "Item"
+ }
+ }
+ }
+ },
+ {
+ "ident": "FnArg",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Receiver": [
+ {
+ "syn": "Receiver"
+ }
+ ],
+ "Typed": [
+ {
+ "syn": "PatType"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "ForeignItem",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Fn": [
+ {
+ "syn": "ForeignItemFn"
+ }
+ ],
+ "Static": [
+ {
+ "syn": "ForeignItemStatic"
+ }
+ ],
+ "Type": [
+ {
+ "syn": "ForeignItemType"
+ }
+ ],
+ "Macro": [
+ {
+ "syn": "ForeignItemMacro"
+ }
+ ],
+ "Verbatim": [
+ {
+ "proc_macro2": "TokenStream"
+ }
+ ]
+ },
+ "exhaustive": false
+ },
+ {
+ "ident": "ForeignItemFn",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "sig": {
+ "syn": "Signature"
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "ForeignItemMacro",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "mac": {
+ "syn": "Macro"
+ },
+ "semi_token": {
+ "option": {
+ "token": "Semi"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ForeignItemStatic",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "static_token": {
+ "token": "Static"
+ },
+ "mutability": {
+ "option": {
+ "token": "Mut"
+ }
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "ty": {
+ "box": {
+ "syn": "Type"
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "ForeignItemType",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "type_token": {
+ "token": "Type"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "GenericArgument",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Lifetime": [
+ {
+ "syn": "Lifetime"
+ }
+ ],
+ "Type": [
+ {
+ "syn": "Type"
+ }
+ ],
+ "Binding": [
+ {
+ "syn": "Binding"
+ }
+ ],
+ "Constraint": [
+ {
+ "syn": "Constraint"
+ }
+ ],
+ "Const": [
+ {
+ "syn": "Expr"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "GenericMethodArgument",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Type": [
+ {
+ "syn": "Type"
+ }
+ ],
+ "Const": [
+ {
+ "syn": "Expr"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "GenericParam",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Type": [
+ {
+ "syn": "TypeParam"
+ }
+ ],
+ "Lifetime": [
+ {
+ "syn": "LifetimeDef"
+ }
+ ],
+ "Const": [
+ {
+ "syn": "ConstParam"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "Generics",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "lt_token": {
+ "option": {
+ "token": "Lt"
+ }
+ },
+ "params": {
+ "punctuated": {
+ "element": {
+ "syn": "GenericParam"
+ },
+ "punct": "Comma"
+ }
+ },
+ "gt_token": {
+ "option": {
+ "token": "Gt"
+ }
+ },
+ "where_clause": {
+ "option": {
+ "syn": "WhereClause"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ImplItem",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Const": [
+ {
+ "syn": "ImplItemConst"
+ }
+ ],
+ "Method": [
+ {
+ "syn": "ImplItemMethod"
+ }
+ ],
+ "Type": [
+ {
+ "syn": "ImplItemType"
+ }
+ ],
+ "Macro": [
+ {
+ "syn": "ImplItemMacro"
+ }
+ ],
+ "Verbatim": [
+ {
+ "proc_macro2": "TokenStream"
+ }
+ ]
+ },
+ "exhaustive": false
+ },
+ {
+ "ident": "ImplItemConst",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "defaultness": {
+ "option": {
+ "token": "Default"
+ }
+ },
+ "const_token": {
+ "token": "Const"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "ty": {
+ "syn": "Type"
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "expr": {
+ "syn": "Expr"
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "ImplItemMacro",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "mac": {
+ "syn": "Macro"
+ },
+ "semi_token": {
+ "option": {
+ "token": "Semi"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ImplItemMethod",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "defaultness": {
+ "option": {
+ "token": "Default"
+ }
+ },
+ "sig": {
+ "syn": "Signature"
+ },
+ "block": {
+ "syn": "Block"
+ }
+ }
+ },
+ {
+ "ident": "ImplItemType",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "defaultness": {
+ "option": {
+ "token": "Default"
+ }
+ },
+ "type_token": {
+ "token": "Type"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "ty": {
+ "syn": "Type"
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "Index",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "index": {
+ "std": "u32"
+ },
+ "span": {
+ "proc_macro2": "Span"
+ }
+ }
+ },
+ {
+ "ident": "Item",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Const": [
+ {
+ "syn": "ItemConst"
+ }
+ ],
+ "Enum": [
+ {
+ "syn": "ItemEnum"
+ }
+ ],
+ "ExternCrate": [
+ {
+ "syn": "ItemExternCrate"
+ }
+ ],
+ "Fn": [
+ {
+ "syn": "ItemFn"
+ }
+ ],
+ "ForeignMod": [
+ {
+ "syn": "ItemForeignMod"
+ }
+ ],
+ "Impl": [
+ {
+ "syn": "ItemImpl"
+ }
+ ],
+ "Macro": [
+ {
+ "syn": "ItemMacro"
+ }
+ ],
+ "Macro2": [
+ {
+ "syn": "ItemMacro2"
+ }
+ ],
+ "Mod": [
+ {
+ "syn": "ItemMod"
+ }
+ ],
+ "Static": [
+ {
+ "syn": "ItemStatic"
+ }
+ ],
+ "Struct": [
+ {
+ "syn": "ItemStruct"
+ }
+ ],
+ "Trait": [
+ {
+ "syn": "ItemTrait"
+ }
+ ],
+ "TraitAlias": [
+ {
+ "syn": "ItemTraitAlias"
+ }
+ ],
+ "Type": [
+ {
+ "syn": "ItemType"
+ }
+ ],
+ "Union": [
+ {
+ "syn": "ItemUnion"
+ }
+ ],
+ "Use": [
+ {
+ "syn": "ItemUse"
+ }
+ ],
+ "Verbatim": [
+ {
+ "proc_macro2": "TokenStream"
+ }
+ ]
+ },
+ "exhaustive": false
+ },
+ {
+ "ident": "ItemConst",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "const_token": {
+ "token": "Const"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "ty": {
+ "box": {
+ "syn": "Type"
+ }
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "ItemEnum",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "enum_token": {
+ "token": "Enum"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "brace_token": {
+ "group": "Brace"
+ },
+ "variants": {
+ "punctuated": {
+ "element": {
+ "syn": "Variant"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ItemExternCrate",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "extern_token": {
+ "token": "Extern"
+ },
+ "crate_token": {
+ "token": "Crate"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "rename": {
+ "option": {
+ "tuple": [
+ {
+ "token": "As"
+ },
+ {
+ "proc_macro2": "Ident"
+ }
+ ]
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "ItemFn",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "sig": {
+ "syn": "Signature"
+ },
+ "block": {
+ "box": {
+ "syn": "Block"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ItemForeignMod",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "abi": {
+ "syn": "Abi"
+ },
+ "brace_token": {
+ "group": "Brace"
+ },
+ "items": {
+ "vec": {
+ "syn": "ForeignItem"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ItemImpl",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "defaultness": {
+ "option": {
+ "token": "Default"
+ }
+ },
+ "unsafety": {
+ "option": {
+ "token": "Unsafe"
+ }
+ },
+ "impl_token": {
+ "token": "Impl"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "trait_": {
+ "option": {
+ "tuple": [
+ {
+ "option": {
+ "token": "Bang"
+ }
+ },
+ {
+ "syn": "Path"
+ },
+ {
+ "token": "For"
+ }
+ ]
+ }
+ },
+ "self_ty": {
+ "box": {
+ "syn": "Type"
+ }
+ },
+ "brace_token": {
+ "group": "Brace"
+ },
+ "items": {
+ "vec": {
+ "syn": "ImplItem"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ItemMacro",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "ident": {
+ "option": {
+ "proc_macro2": "Ident"
+ }
+ },
+ "mac": {
+ "syn": "Macro"
+ },
+ "semi_token": {
+ "option": {
+ "token": "Semi"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ItemMacro2",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "macro_token": {
+ "token": "Macro"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "rules": {
+ "proc_macro2": "TokenStream"
+ }
+ }
+ },
+ {
+ "ident": "ItemMod",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "mod_token": {
+ "token": "Mod"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "content": {
+ "option": {
+ "tuple": [
+ {
+ "group": "Brace"
+ },
+ {
+ "vec": {
+ "syn": "Item"
+ }
+ }
+ ]
+ }
+ },
+ "semi": {
+ "option": {
+ "token": "Semi"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ItemStatic",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "static_token": {
+ "token": "Static"
+ },
+ "mutability": {
+ "option": {
+ "token": "Mut"
+ }
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "ty": {
+ "box": {
+ "syn": "Type"
+ }
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "ItemStruct",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "struct_token": {
+ "token": "Struct"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "fields": {
+ "syn": "Fields"
+ },
+ "semi_token": {
+ "option": {
+ "token": "Semi"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ItemTrait",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "unsafety": {
+ "option": {
+ "token": "Unsafe"
+ }
+ },
+ "auto_token": {
+ "option": {
+ "token": "Auto"
+ }
+ },
+ "trait_token": {
+ "token": "Trait"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "colon_token": {
+ "option": {
+ "token": "Colon"
+ }
+ },
+ "supertraits": {
+ "punctuated": {
+ "element": {
+ "syn": "TypeParamBound"
+ },
+ "punct": "Add"
+ }
+ },
+ "brace_token": {
+ "group": "Brace"
+ },
+ "items": {
+ "vec": {
+ "syn": "TraitItem"
+ }
+ }
+ }
+ },
+ {
+ "ident": "ItemTraitAlias",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "trait_token": {
+ "token": "Trait"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "TypeParamBound"
+ },
+ "punct": "Add"
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "ItemType",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "type_token": {
+ "token": "Type"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "ty": {
+ "box": {
+ "syn": "Type"
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "ItemUnion",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "union_token": {
+ "token": "Union"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "fields": {
+ "syn": "FieldsNamed"
+ }
+ }
+ },
+ {
+ "ident": "ItemUse",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "vis": {
+ "syn": "Visibility"
+ },
+ "use_token": {
+ "token": "Use"
+ },
+ "leading_colon": {
+ "option": {
+ "token": "Colon2"
+ }
+ },
+ "tree": {
+ "syn": "UseTree"
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "Label",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "name": {
+ "syn": "Lifetime"
+ },
+ "colon_token": {
+ "token": "Colon"
+ }
+ }
+ },
+ {
+ "ident": "Lifetime",
+ "features": {
+ "any": []
+ },
+ "fields": {
+ "apostrophe": {
+ "proc_macro2": "Span"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ }
+ }
+ },
+ {
+ "ident": "LifetimeDef",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "lifetime": {
+ "syn": "Lifetime"
+ },
+ "colon_token": {
+ "option": {
+ "token": "Colon"
+ }
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "Lifetime"
+ },
+ "punct": "Add"
+ }
+ }
+ }
+ },
+ {
+ "ident": "Lit",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Str": [
+ {
+ "syn": "LitStr"
+ }
+ ],
+ "ByteStr": [
+ {
+ "syn": "LitByteStr"
+ }
+ ],
+ "Byte": [
+ {
+ "syn": "LitByte"
+ }
+ ],
+ "Char": [
+ {
+ "syn": "LitChar"
+ }
+ ],
+ "Int": [
+ {
+ "syn": "LitInt"
+ }
+ ],
+ "Float": [
+ {
+ "syn": "LitFloat"
+ }
+ ],
+ "Bool": [
+ {
+ "syn": "LitBool"
+ }
+ ],
+ "Verbatim": [
+ {
+ "proc_macro2": "Literal"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "LitBool",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "value": {
+ "std": "bool"
+ },
+ "span": {
+ "proc_macro2": "Span"
+ }
+ }
+ },
+ {
+ "ident": "LitByte",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ }
+ },
+ {
+ "ident": "LitByteStr",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ }
+ },
+ {
+ "ident": "LitChar",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ }
+ },
+ {
+ "ident": "LitFloat",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ }
+ },
+ {
+ "ident": "LitInt",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ }
+ },
+ {
+ "ident": "LitStr",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ }
+ },
+ {
+ "ident": "Local",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "let_token": {
+ "token": "Let"
+ },
+ "pat": {
+ "syn": "Pat"
+ },
+ "init": {
+ "option": {
+ "tuple": [
+ {
+ "token": "Eq"
+ },
+ {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ ]
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "Macro",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "path": {
+ "syn": "Path"
+ },
+ "bang_token": {
+ "token": "Bang"
+ },
+ "delimiter": {
+ "syn": "MacroDelimiter"
+ },
+ "tokens": {
+ "proc_macro2": "TokenStream"
+ }
+ }
+ },
+ {
+ "ident": "MacroDelimiter",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Paren": [
+ {
+ "group": "Paren"
+ }
+ ],
+ "Brace": [
+ {
+ "group": "Brace"
+ }
+ ],
+ "Bracket": [
+ {
+ "group": "Bracket"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "Member",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Named": [
+ {
+ "proc_macro2": "Ident"
+ }
+ ],
+ "Unnamed": [
+ {
+ "syn": "Index"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "Meta",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Path": [
+ {
+ "syn": "Path"
+ }
+ ],
+ "List": [
+ {
+ "syn": "MetaList"
+ }
+ ],
+ "NameValue": [
+ {
+ "syn": "MetaNameValue"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "MetaList",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "path": {
+ "syn": "Path"
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "nested": {
+ "punctuated": {
+ "element": {
+ "syn": "NestedMeta"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "MetaNameValue",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "path": {
+ "syn": "Path"
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "lit": {
+ "syn": "Lit"
+ }
+ }
+ },
+ {
+ "ident": "MethodTurbofish",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "colon2_token": {
+ "token": "Colon2"
+ },
+ "lt_token": {
+ "token": "Lt"
+ },
+ "args": {
+ "punctuated": {
+ "element": {
+ "syn": "GenericMethodArgument"
+ },
+ "punct": "Comma"
+ }
+ },
+ "gt_token": {
+ "token": "Gt"
+ }
+ }
+ },
+ {
+ "ident": "NestedMeta",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Meta": [
+ {
+ "syn": "Meta"
+ }
+ ],
+ "Lit": [
+ {
+ "syn": "Lit"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "ParenthesizedGenericArguments",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "paren_token": {
+ "group": "Paren"
+ },
+ "inputs": {
+ "punctuated": {
+ "element": {
+ "syn": "Type"
+ },
+ "punct": "Comma"
+ }
+ },
+ "output": {
+ "syn": "ReturnType"
+ }
+ }
+ },
+ {
+ "ident": "Pat",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Box": [
+ {
+ "syn": "PatBox"
+ }
+ ],
+ "Ident": [
+ {
+ "syn": "PatIdent"
+ }
+ ],
+ "Lit": [
+ {
+ "syn": "PatLit"
+ }
+ ],
+ "Macro": [
+ {
+ "syn": "PatMacro"
+ }
+ ],
+ "Or": [
+ {
+ "syn": "PatOr"
+ }
+ ],
+ "Path": [
+ {
+ "syn": "PatPath"
+ }
+ ],
+ "Range": [
+ {
+ "syn": "PatRange"
+ }
+ ],
+ "Reference": [
+ {
+ "syn": "PatReference"
+ }
+ ],
+ "Rest": [
+ {
+ "syn": "PatRest"
+ }
+ ],
+ "Slice": [
+ {
+ "syn": "PatSlice"
+ }
+ ],
+ "Struct": [
+ {
+ "syn": "PatStruct"
+ }
+ ],
+ "Tuple": [
+ {
+ "syn": "PatTuple"
+ }
+ ],
+ "TupleStruct": [
+ {
+ "syn": "PatTupleStruct"
+ }
+ ],
+ "Type": [
+ {
+ "syn": "PatType"
+ }
+ ],
+ "Verbatim": [
+ {
+ "proc_macro2": "TokenStream"
+ }
+ ],
+ "Wild": [
+ {
+ "syn": "PatWild"
+ }
+ ]
+ },
+ "exhaustive": false
+ },
+ {
+ "ident": "PatBox",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "box_token": {
+ "token": "Box"
+ },
+ "pat": {
+ "box": {
+ "syn": "Pat"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatIdent",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "by_ref": {
+ "option": {
+ "token": "Ref"
+ }
+ },
+ "mutability": {
+ "option": {
+ "token": "Mut"
+ }
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "subpat": {
+ "option": {
+ "tuple": [
+ {
+ "token": "At"
+ },
+ {
+ "box": {
+ "syn": "Pat"
+ }
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatLit",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "expr": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatMacro",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "mac": {
+ "syn": "Macro"
+ }
+ }
+ },
+ {
+ "ident": "PatOr",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "leading_vert": {
+ "option": {
+ "token": "Or"
+ }
+ },
+ "cases": {
+ "punctuated": {
+ "element": {
+ "syn": "Pat"
+ },
+ "punct": "Or"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatPath",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "qself": {
+ "option": {
+ "syn": "QSelf"
+ }
+ },
+ "path": {
+ "syn": "Path"
+ }
+ }
+ },
+ {
+ "ident": "PatRange",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "lo": {
+ "box": {
+ "syn": "Expr"
+ }
+ },
+ "limits": {
+ "syn": "RangeLimits"
+ },
+ "hi": {
+ "box": {
+ "syn": "Expr"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatReference",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "and_token": {
+ "token": "And"
+ },
+ "mutability": {
+ "option": {
+ "token": "Mut"
+ }
+ },
+ "pat": {
+ "box": {
+ "syn": "Pat"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatRest",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "dot2_token": {
+ "token": "Dot2"
+ }
+ }
+ },
+ {
+ "ident": "PatSlice",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "bracket_token": {
+ "group": "Bracket"
+ },
+ "elems": {
+ "punctuated": {
+ "element": {
+ "syn": "Pat"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatStruct",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "path": {
+ "syn": "Path"
+ },
+ "brace_token": {
+ "group": "Brace"
+ },
+ "fields": {
+ "punctuated": {
+ "element": {
+ "syn": "FieldPat"
+ },
+ "punct": "Comma"
+ }
+ },
+ "dot2_token": {
+ "option": {
+ "token": "Dot2"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatTuple",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "elems": {
+ "punctuated": {
+ "element": {
+ "syn": "Pat"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatTupleStruct",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "path": {
+ "syn": "Path"
+ },
+ "pat": {
+ "syn": "PatTuple"
+ }
+ }
+ },
+ {
+ "ident": "PatType",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "pat": {
+ "box": {
+ "syn": "Pat"
+ }
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "ty": {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PatWild",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "underscore_token": {
+ "token": "Underscore"
+ }
+ }
+ },
+ {
+ "ident": "Path",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "leading_colon": {
+ "option": {
+ "token": "Colon2"
+ }
+ },
+ "segments": {
+ "punctuated": {
+ "element": {
+ "syn": "PathSegment"
+ },
+ "punct": "Colon2"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PathArguments",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "None": [],
+ "AngleBracketed": [
+ {
+ "syn": "AngleBracketedGenericArguments"
+ }
+ ],
+ "Parenthesized": [
+ {
+ "syn": "ParenthesizedGenericArguments"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "PathSegment",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "arguments": {
+ "syn": "PathArguments"
+ }
+ }
+ },
+ {
+ "ident": "PredicateEq",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "lhs_ty": {
+ "syn": "Type"
+ },
+ "eq_token": {
+ "token": "Eq"
+ },
+ "rhs_ty": {
+ "syn": "Type"
+ }
+ }
+ },
+ {
+ "ident": "PredicateLifetime",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "lifetime": {
+ "syn": "Lifetime"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "Lifetime"
+ },
+ "punct": "Add"
+ }
+ }
+ }
+ },
+ {
+ "ident": "PredicateType",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "lifetimes": {
+ "option": {
+ "syn": "BoundLifetimes"
+ }
+ },
+ "bounded_ty": {
+ "syn": "Type"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "TypeParamBound"
+ },
+ "punct": "Add"
+ }
+ }
+ }
+ },
+ {
+ "ident": "QSelf",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "lt_token": {
+ "token": "Lt"
+ },
+ "ty": {
+ "box": {
+ "syn": "Type"
+ }
+ },
+ "position": {
+ "std": "usize"
+ },
+ "as_token": {
+ "option": {
+ "token": "As"
+ }
+ },
+ "gt_token": {
+ "token": "Gt"
+ }
+ }
+ },
+ {
+ "ident": "RangeLimits",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "HalfOpen": [
+ {
+ "token": "Dot2"
+ }
+ ],
+ "Closed": [
+ {
+ "token": "DotDotEq"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "Receiver",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "reference": {
+ "option": {
+ "tuple": [
+ {
+ "token": "And"
+ },
+ {
+ "option": {
+ "syn": "Lifetime"
+ }
+ }
+ ]
+ }
+ },
+ "mutability": {
+ "option": {
+ "token": "Mut"
+ }
+ },
+ "self_token": {
+ "token": "SelfValue"
+ }
+ }
+ },
+ {
+ "ident": "ReturnType",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Default": [],
+ "Type": [
+ {
+ "token": "RArrow"
+ },
+ {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "ident": "Signature",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "constness": {
+ "option": {
+ "token": "Const"
+ }
+ },
+ "asyncness": {
+ "option": {
+ "token": "Async"
+ }
+ },
+ "unsafety": {
+ "option": {
+ "token": "Unsafe"
+ }
+ },
+ "abi": {
+ "option": {
+ "syn": "Abi"
+ }
+ },
+ "fn_token": {
+ "token": "Fn"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "inputs": {
+ "punctuated": {
+ "element": {
+ "syn": "FnArg"
+ },
+ "punct": "Comma"
+ }
+ },
+ "variadic": {
+ "option": {
+ "syn": "Variadic"
+ }
+ },
+ "output": {
+ "syn": "ReturnType"
+ }
+ }
+ },
+ {
+ "ident": "Stmt",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Local": [
+ {
+ "syn": "Local"
+ }
+ ],
+ "Item": [
+ {
+ "syn": "Item"
+ }
+ ],
+ "Expr": [
+ {
+ "syn": "Expr"
+ }
+ ],
+ "Semi": [
+ {
+ "syn": "Expr"
+ },
+ {
+ "token": "Semi"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "TraitBound",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "paren_token": {
+ "option": {
+ "group": "Paren"
+ }
+ },
+ "modifier": {
+ "syn": "TraitBoundModifier"
+ },
+ "lifetimes": {
+ "option": {
+ "syn": "BoundLifetimes"
+ }
+ },
+ "path": {
+ "syn": "Path"
+ }
+ }
+ },
+ {
+ "ident": "TraitBoundModifier",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "None": [],
+ "Maybe": [
+ {
+ "token": "Question"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "TraitItem",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Const": [
+ {
+ "syn": "TraitItemConst"
+ }
+ ],
+ "Method": [
+ {
+ "syn": "TraitItemMethod"
+ }
+ ],
+ "Type": [
+ {
+ "syn": "TraitItemType"
+ }
+ ],
+ "Macro": [
+ {
+ "syn": "TraitItemMacro"
+ }
+ ],
+ "Verbatim": [
+ {
+ "proc_macro2": "TokenStream"
+ }
+ ]
+ },
+ "exhaustive": false
+ },
+ {
+ "ident": "TraitItemConst",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "const_token": {
+ "token": "Const"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon_token": {
+ "token": "Colon"
+ },
+ "ty": {
+ "syn": "Type"
+ },
+ "default": {
+ "option": {
+ "tuple": [
+ {
+ "token": "Eq"
+ },
+ {
+ "syn": "Expr"
+ }
+ ]
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "TraitItemMacro",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "mac": {
+ "syn": "Macro"
+ },
+ "semi_token": {
+ "option": {
+ "token": "Semi"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TraitItemMethod",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "sig": {
+ "syn": "Signature"
+ },
+ "default": {
+ "option": {
+ "syn": "Block"
+ }
+ },
+ "semi_token": {
+ "option": {
+ "token": "Semi"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TraitItemType",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "type_token": {
+ "token": "Type"
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "generics": {
+ "syn": "Generics"
+ },
+ "colon_token": {
+ "option": {
+ "token": "Colon"
+ }
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "TypeParamBound"
+ },
+ "punct": "Add"
+ }
+ },
+ "default": {
+ "option": {
+ "tuple": [
+ {
+ "token": "Eq"
+ },
+ {
+ "syn": "Type"
+ }
+ ]
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ }
+ }
+ },
+ {
+ "ident": "Type",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Array": [
+ {
+ "syn": "TypeArray"
+ }
+ ],
+ "BareFn": [
+ {
+ "syn": "TypeBareFn"
+ }
+ ],
+ "Group": [
+ {
+ "syn": "TypeGroup"
+ }
+ ],
+ "ImplTrait": [
+ {
+ "syn": "TypeImplTrait"
+ }
+ ],
+ "Infer": [
+ {
+ "syn": "TypeInfer"
+ }
+ ],
+ "Macro": [
+ {
+ "syn": "TypeMacro"
+ }
+ ],
+ "Never": [
+ {
+ "syn": "TypeNever"
+ }
+ ],
+ "Paren": [
+ {
+ "syn": "TypeParen"
+ }
+ ],
+ "Path": [
+ {
+ "syn": "TypePath"
+ }
+ ],
+ "Ptr": [
+ {
+ "syn": "TypePtr"
+ }
+ ],
+ "Reference": [
+ {
+ "syn": "TypeReference"
+ }
+ ],
+ "Slice": [
+ {
+ "syn": "TypeSlice"
+ }
+ ],
+ "TraitObject": [
+ {
+ "syn": "TypeTraitObject"
+ }
+ ],
+ "Tuple": [
+ {
+ "syn": "TypeTuple"
+ }
+ ],
+ "Verbatim": [
+ {
+ "proc_macro2": "TokenStream"
+ }
+ ]
+ },
+ "exhaustive": false
+ },
+ {
+ "ident": "TypeArray",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "bracket_token": {
+ "group": "Bracket"
+ },
+ "elem": {
+ "box": {
+ "syn": "Type"
+ }
+ },
+ "semi_token": {
+ "token": "Semi"
+ },
+ "len": {
+ "syn": "Expr"
+ }
+ }
+ },
+ {
+ "ident": "TypeBareFn",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "lifetimes": {
+ "option": {
+ "syn": "BoundLifetimes"
+ }
+ },
+ "unsafety": {
+ "option": {
+ "token": "Unsafe"
+ }
+ },
+ "abi": {
+ "option": {
+ "syn": "Abi"
+ }
+ },
+ "fn_token": {
+ "token": "Fn"
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "inputs": {
+ "punctuated": {
+ "element": {
+ "syn": "BareFnArg"
+ },
+ "punct": "Comma"
+ }
+ },
+ "variadic": {
+ "option": {
+ "syn": "Variadic"
+ }
+ },
+ "output": {
+ "syn": "ReturnType"
+ }
+ }
+ },
+ {
+ "ident": "TypeGroup",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "group_token": {
+ "group": "Group"
+ },
+ "elem": {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TypeImplTrait",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "impl_token": {
+ "token": "Impl"
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "TypeParamBound"
+ },
+ "punct": "Add"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TypeInfer",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "underscore_token": {
+ "token": "Underscore"
+ }
+ }
+ },
+ {
+ "ident": "TypeMacro",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "mac": {
+ "syn": "Macro"
+ }
+ }
+ },
+ {
+ "ident": "TypeNever",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "bang_token": {
+ "token": "Bang"
+ }
+ }
+ },
+ {
+ "ident": "TypeParam",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon_token": {
+ "option": {
+ "token": "Colon"
+ }
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "TypeParamBound"
+ },
+ "punct": "Add"
+ }
+ },
+ "eq_token": {
+ "option": {
+ "token": "Eq"
+ }
+ },
+ "default": {
+ "option": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TypeParamBound",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Trait": [
+ {
+ "syn": "TraitBound"
+ }
+ ],
+ "Lifetime": [
+ {
+ "syn": "Lifetime"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "TypeParen",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "paren_token": {
+ "group": "Paren"
+ },
+ "elem": {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TypePath",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "qself": {
+ "option": {
+ "syn": "QSelf"
+ }
+ },
+ "path": {
+ "syn": "Path"
+ }
+ }
+ },
+ {
+ "ident": "TypePtr",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "star_token": {
+ "token": "Star"
+ },
+ "const_token": {
+ "option": {
+ "token": "Const"
+ }
+ },
+ "mutability": {
+ "option": {
+ "token": "Mut"
+ }
+ },
+ "elem": {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TypeReference",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "and_token": {
+ "token": "And"
+ },
+ "lifetime": {
+ "option": {
+ "syn": "Lifetime"
+ }
+ },
+ "mutability": {
+ "option": {
+ "token": "Mut"
+ }
+ },
+ "elem": {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TypeSlice",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "bracket_token": {
+ "group": "Bracket"
+ },
+ "elem": {
+ "box": {
+ "syn": "Type"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TypeTraitObject",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "dyn_token": {
+ "option": {
+ "token": "Dyn"
+ }
+ },
+ "bounds": {
+ "punctuated": {
+ "element": {
+ "syn": "TypeParamBound"
+ },
+ "punct": "Add"
+ }
+ }
+ }
+ },
+ {
+ "ident": "TypeTuple",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "paren_token": {
+ "group": "Paren"
+ },
+ "elems": {
+ "punctuated": {
+ "element": {
+ "syn": "Type"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "UnOp",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Deref": [
+ {
+ "token": "Star"
+ }
+ ],
+ "Not": [
+ {
+ "token": "Bang"
+ }
+ ],
+ "Neg": [
+ {
+ "token": "Sub"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "UseGlob",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "star_token": {
+ "token": "Star"
+ }
+ }
+ },
+ {
+ "ident": "UseGroup",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "brace_token": {
+ "group": "Brace"
+ },
+ "items": {
+ "punctuated": {
+ "element": {
+ "syn": "UseTree"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "UseName",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "ident": {
+ "proc_macro2": "Ident"
+ }
+ }
+ },
+ {
+ "ident": "UsePath",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "colon2_token": {
+ "token": "Colon2"
+ },
+ "tree": {
+ "box": {
+ "syn": "UseTree"
+ }
+ }
+ }
+ },
+ {
+ "ident": "UseRename",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "fields": {
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "as_token": {
+ "token": "As"
+ },
+ "rename": {
+ "proc_macro2": "Ident"
+ }
+ }
+ },
+ {
+ "ident": "UseTree",
+ "features": {
+ "any": [
+ "full"
+ ]
+ },
+ "variants": {
+ "Path": [
+ {
+ "syn": "UsePath"
+ }
+ ],
+ "Name": [
+ {
+ "syn": "UseName"
+ }
+ ],
+ "Rename": [
+ {
+ "syn": "UseRename"
+ }
+ ],
+ "Glob": [
+ {
+ "syn": "UseGlob"
+ }
+ ],
+ "Group": [
+ {
+ "syn": "UseGroup"
+ }
+ ]
+ }
+ },
+ {
+ "ident": "Variadic",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "dots": {
+ "token": "Dot3"
+ }
+ }
+ },
+ {
+ "ident": "Variant",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "attrs": {
+ "vec": {
+ "syn": "Attribute"
+ }
+ },
+ "ident": {
+ "proc_macro2": "Ident"
+ },
+ "fields": {
+ "syn": "Fields"
+ },
+ "discriminant": {
+ "option": {
+ "tuple": [
+ {
+ "token": "Eq"
+ },
+ {
+ "syn": "Expr"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "ident": "VisCrate",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "crate_token": {
+ "token": "Crate"
+ }
+ }
+ },
+ {
+ "ident": "VisPublic",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "pub_token": {
+ "token": "Pub"
+ }
+ }
+ },
+ {
+ "ident": "VisRestricted",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "pub_token": {
+ "token": "Pub"
+ },
+ "paren_token": {
+ "group": "Paren"
+ },
+ "in_token": {
+ "option": {
+ "token": "In"
+ }
+ },
+ "path": {
+ "box": {
+ "syn": "Path"
+ }
+ }
+ }
+ },
+ {
+ "ident": "Visibility",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Public": [
+ {
+ "syn": "VisPublic"
+ }
+ ],
+ "Crate": [
+ {
+ "syn": "VisCrate"
+ }
+ ],
+ "Restricted": [
+ {
+ "syn": "VisRestricted"
+ }
+ ],
+ "Inherited": []
+ }
+ },
+ {
+ "ident": "WhereClause",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "fields": {
+ "where_token": {
+ "token": "Where"
+ },
+ "predicates": {
+ "punctuated": {
+ "element": {
+ "syn": "WherePredicate"
+ },
+ "punct": "Comma"
+ }
+ }
+ }
+ },
+ {
+ "ident": "WherePredicate",
+ "features": {
+ "any": [
+ "derive",
+ "full"
+ ]
+ },
+ "variants": {
+ "Type": [
+ {
+ "syn": "PredicateType"
+ }
+ ],
+ "Lifetime": [
+ {
+ "syn": "PredicateLifetime"
+ }
+ ],
+ "Eq": [
+ {
+ "syn": "PredicateEq"
+ }
+ ]
+ }
+ }
+ ],
+ "tokens": {
+ "Abstract": "abstract",
+ "Add": "+",
+ "AddEq": "+=",
+ "And": "&",
+ "AndAnd": "&&",
+ "AndEq": "&=",
+ "As": "as",
+ "Async": "async",
+ "At": "@",
+ "Auto": "auto",
+ "Await": "await",
+ "Bang": "!",
+ "Become": "become",
+ "Box": "box",
+ "Break": "break",
+ "Caret": "^",
+ "CaretEq": "^=",
+ "Colon": ":",
+ "Colon2": "::",
+ "Comma": ",",
+ "Const": "const",
+ "Continue": "continue",
+ "Crate": "crate",
+ "Default": "default",
+ "Div": "/",
+ "DivEq": "/=",
+ "Do": "do",
+ "Dollar": "$",
+ "Dot": ".",
+ "Dot2": "..",
+ "Dot3": "...",
+ "DotDotEq": "..=",
+ "Dyn": "dyn",
+ "Else": "else",
+ "Enum": "enum",
+ "Eq": "=",
+ "EqEq": "==",
+ "Extern": "extern",
+ "FatArrow": "=>",
+ "Final": "final",
+ "Fn": "fn",
+ "For": "for",
+ "Ge": ">=",
+ "Gt": ">",
+ "If": "if",
+ "Impl": "impl",
+ "In": "in",
+ "LArrow": "<-",
+ "Le": "<=",
+ "Let": "let",
+ "Loop": "loop",
+ "Lt": "<",
+ "Macro": "macro",
+ "Match": "match",
+ "Mod": "mod",
+ "Move": "move",
+ "MulEq": "*=",
+ "Mut": "mut",
+ "Ne": "!=",
+ "Or": "|",
+ "OrEq": "|=",
+ "OrOr": "||",
+ "Override": "override",
+ "Pound": "#",
+ "Priv": "priv",
+ "Pub": "pub",
+ "Question": "?",
+ "RArrow": "->",
+ "Ref": "ref",
+ "Rem": "%",
+ "RemEq": "%=",
+ "Return": "return",
+ "SelfType": "Self",
+ "SelfValue": "self",
+ "Semi": ";",
+ "Shl": "<<",
+ "ShlEq": "<<=",
+ "Shr": ">>",
+ "ShrEq": ">>=",
+ "Star": "*",
+ "Static": "static",
+ "Struct": "struct",
+ "Sub": "-",
+ "SubEq": "-=",
+ "Super": "super",
+ "Tilde": "~",
+ "Trait": "trait",
+ "Try": "try",
+ "Type": "type",
+ "Typeof": "typeof",
+ "Underscore": "_",
+ "Union": "union",
+ "Unsafe": "unsafe",
+ "Unsized": "unsized",
+ "Use": "use",
+ "Virtual": "virtual",
+ "Where": "where",
+ "While": "while",
+ "Yield": "yield"
+ }
+}
diff --git a/syn/tests/common/eq.rs b/syn/tests/common/eq.rs
new file mode 100644
index 0000000..098f833
--- /dev/null
+++ b/syn/tests/common/eq.rs
@@ -0,0 +1,459 @@
+extern crate rustc_data_structures;
+extern crate rustc_span;
+extern crate rustc_target;
+extern crate syntax;
+
+use std::mem;
+
+use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_span::{Span, SyntaxContext, DUMMY_SP};
+use syntax::ast::{
+ AngleBracketedArgs, AnonConst, Arm, AsmDialect, AssocItem, AssocItemKind, AssocTyConstraint,
+ AssocTyConstraintKind, AttrId, AttrItem, AttrKind, AttrStyle, Attribute, BareFnTy, BinOpKind,
+ BindingMode, Block, BlockCheckMode, BorrowKind, CaptureBy, Constness, Crate, CrateSugar,
+ Defaultness, EnumDef, Expr, ExprKind, Extern, Field, FieldPat, FloatTy, FnDecl, FnHeader,
+ FnSig, ForeignItem, ForeignItemKind, ForeignMod, FunctionRetTy, GenericArg, GenericArgs,
+ GenericBound, GenericParam, GenericParamKind, Generics, GlobalAsm, Ident, ImplPolarity,
+ InlineAsm, InlineAsmOutput, IntTy, IsAsync, IsAuto, Item, ItemKind, Label, Lifetime, Lit,
+ LitFloatType, LitIntType, LitKind, Local, Mac, MacArgs, MacDelimiter, MacStmtStyle, MacroDef,
+ Mod, Movability, MutTy, Mutability, NodeId, Param, ParenthesizedArgs, Pat, PatKind, Path,
+ PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind, StrLit,
+ StrStyle, StructField, TraitBoundModifier, TraitObjectSyntax, TraitRef, Ty, TyKind, UintTy,
+ UnOp, UnsafeSource, Unsafety, UseTree, UseTreeKind, Variant, VariantData, VisibilityKind,
+ WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate, WhereRegionPredicate,
+};
+use syntax::ptr::P;
+use syntax::source_map::Spanned;
+use syntax::symbol::{sym, Symbol};
+use syntax::token::{self, DelimToken, Token, TokenKind};
+use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use syntax::util::comments;
+
+pub trait SpanlessEq {
+ fn eq(&self, other: &Self) -> bool;
+}
+
+impl<T: SpanlessEq> SpanlessEq for P<T> {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&**self, &**other)
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for Lrc<T> {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&**self, &**other)
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for Option<T> {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (None, None) => true,
+ (Some(this), Some(other)) => SpanlessEq::eq(this, other),
+ _ => false,
+ }
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for Vec<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.len() == other.len() && self.iter().zip(other).all(|(a, b)| SpanlessEq::eq(a, b))
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for ThinVec<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.len() == other.len()
+ && self
+ .iter()
+ .zip(other.iter())
+ .all(|(a, b)| SpanlessEq::eq(a, b))
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for Spanned<T> {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&self.node, &other.node)
+ }
+}
+
+impl<A: SpanlessEq, B: SpanlessEq> SpanlessEq for (A, B) {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&self.0, &other.0) && SpanlessEq::eq(&self.1, &other.1)
+ }
+}
+
+impl<A: SpanlessEq, B: SpanlessEq, C: SpanlessEq> SpanlessEq for (A, B, C) {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&self.0, &other.0)
+ && SpanlessEq::eq(&self.1, &other.1)
+ && SpanlessEq::eq(&self.2, &other.2)
+ }
+}
+
+macro_rules! spanless_eq_true {
+ ($name:ident) => {
+ impl SpanlessEq for $name {
+ fn eq(&self, _other: &Self) -> bool {
+ true
+ }
+ }
+ };
+}
+
+spanless_eq_true!(Span);
+spanless_eq_true!(DelimSpan);
+spanless_eq_true!(AttrId);
+spanless_eq_true!(NodeId);
+spanless_eq_true!(SyntaxContext);
+
+macro_rules! spanless_eq_partial_eq {
+ ($name:ident) => {
+ impl SpanlessEq for $name {
+ fn eq(&self, other: &Self) -> bool {
+ PartialEq::eq(self, other)
+ }
+ }
+ };
+}
+
+spanless_eq_partial_eq!(bool);
+spanless_eq_partial_eq!(u8);
+spanless_eq_partial_eq!(u16);
+spanless_eq_partial_eq!(u128);
+spanless_eq_partial_eq!(usize);
+spanless_eq_partial_eq!(char);
+spanless_eq_partial_eq!(Symbol);
+spanless_eq_partial_eq!(DelimToken);
+
+macro_rules! spanless_eq_struct {
+ {
+ $name:ident;
+ $([$field:ident $other:ident])*
+ $(![$ignore:ident])*
+ } => {
+ impl SpanlessEq for $name {
+ fn eq(&self, other: &Self) -> bool {
+ let $name { $($field,)* $($ignore: _,)* } = self;
+ let $name { $($field: $other,)* $($ignore: _,)* } = other;
+ $(SpanlessEq::eq($field, $other))&&*
+ }
+ }
+ };
+
+ {
+ $name:ident;
+ $([$field:ident $other:ident])*
+ $next:ident
+ $($rest:ident)*
+ $(!$ignore:ident)*
+ } => {
+ spanless_eq_struct! {
+ $name;
+ $([$field $other])*
+ [$next other]
+ $($rest)*
+ $(!$ignore)*
+ }
+ };
+
+ {
+ $name:ident;
+ $([$field:ident $other:ident])*
+ $(![$ignore:ident])*
+ !$next:ident
+ $(!$rest:ident)*
+ } => {
+ spanless_eq_struct! {
+ $name;
+ $([$field $other])*
+ $(![$ignore])*
+ ![$next]
+ $(!$rest)*
+ }
+ };
+}
+
+macro_rules! spanless_eq_enum {
+ {
+ $name:ident;
+ $([$variant:ident $([$field:tt $this:ident $other:ident])*])*
+ } => {
+ impl SpanlessEq for $name {
+ fn eq(&self, other: &Self) -> bool {
+ match self {
+ $(
+ $name::$variant { .. } => {}
+ )*
+ }
+ #[allow(unreachable_patterns)]
+ match (self, other) {
+ $(
+ (
+ $name::$variant { $($field: $this),* },
+ $name::$variant { $($field: $other),* },
+ ) => {
+ true $(&& SpanlessEq::eq($this, $other))*
+ }
+ )*
+ _ => false,
+ }
+ }
+ }
+ };
+
+ {
+ $name:ident;
+ $([$variant:ident $($fields:tt)*])*
+ $next:ident [$($named:tt)*] ( $i:tt $($field:tt)* )
+ $($rest:tt)*
+ } => {
+ spanless_eq_enum! {
+ $name;
+ $([$variant $($fields)*])*
+ $next [$($named)* [$i this other]] ( $($field)* )
+ $($rest)*
+ }
+ };
+
+ {
+ $name:ident;
+ $([$variant:ident $($fields:tt)*])*
+ $next:ident [$($named:tt)*] ()
+ $($rest:tt)*
+ } => {
+ spanless_eq_enum! {
+ $name;
+ $([$variant $($fields)*])*
+ [$next $($named)*]
+ $($rest)*
+ }
+ };
+
+ {
+ $name:ident;
+ $([$variant:ident $($fields:tt)*])*
+ $next:ident ( $($field:tt)* )
+ $($rest:tt)*
+ } => {
+ spanless_eq_enum! {
+ $name;
+ $([$variant $($fields)*])*
+ $next [] ( $($field)* )
+ $($rest)*
+ }
+ };
+
+ {
+ $name:ident;
+ $([$variant:ident $($fields:tt)*])*
+ $next:ident
+ $($rest:tt)*
+ } => {
+ spanless_eq_enum! {
+ $name;
+ $([$variant $($fields)*])*
+ [$next]
+ $($rest)*
+ }
+ };
+}
+
+spanless_eq_struct!(AngleBracketedArgs; span args constraints);
+spanless_eq_struct!(AnonConst; id value);
+spanless_eq_struct!(Arm; attrs pat guard body span id is_placeholder);
+spanless_eq_struct!(AssocItem; attrs id span vis ident defaultness generics kind !tokens);
+spanless_eq_struct!(AssocTyConstraint; id ident kind span);
+spanless_eq_struct!(AttrItem; path args);
+spanless_eq_struct!(Attribute; kind id style span);
+spanless_eq_struct!(BareFnTy; unsafety ext generic_params decl);
+spanless_eq_struct!(Block; stmts id rules span);
+spanless_eq_struct!(Crate; module attrs span);
+spanless_eq_struct!(EnumDef; variants);
+spanless_eq_struct!(Expr; id kind span attrs);
+spanless_eq_struct!(Field; attrs id span ident expr is_shorthand is_placeholder);
+spanless_eq_struct!(FieldPat; ident pat is_shorthand attrs id span is_placeholder);
+spanless_eq_struct!(FnDecl; inputs output);
+spanless_eq_struct!(FnHeader; constness asyncness unsafety ext);
+spanless_eq_struct!(FnSig; header decl);
+spanless_eq_struct!(ForeignItem; attrs id span vis ident kind tokens);
+spanless_eq_struct!(ForeignMod; abi items);
+spanless_eq_struct!(GenericParam; id ident attrs bounds is_placeholder kind);
+spanless_eq_struct!(Generics; params where_clause span);
+spanless_eq_struct!(GlobalAsm; asm);
+spanless_eq_struct!(InlineAsm; asm asm_str_style outputs inputs clobbers volatile alignstack dialect);
+spanless_eq_struct!(InlineAsmOutput; constraint expr is_rw is_indirect);
+spanless_eq_struct!(Item; attrs id span vis ident kind !tokens);
+spanless_eq_struct!(Label; ident);
+spanless_eq_struct!(Lifetime; id ident);
+spanless_eq_struct!(Lit; token kind span);
+spanless_eq_struct!(Local; pat ty init id span attrs);
+spanless_eq_struct!(Mac; path args prior_type_ascription);
+spanless_eq_struct!(MacroDef; body legacy);
+spanless_eq_struct!(Mod; inner items inline);
+spanless_eq_struct!(MutTy; ty mutbl);
+spanless_eq_struct!(Param; attrs ty pat id span is_placeholder);
+spanless_eq_struct!(ParenthesizedArgs; span inputs output);
+spanless_eq_struct!(Pat; id kind span);
+spanless_eq_struct!(Path; span segments);
+spanless_eq_struct!(PathSegment; ident id args);
+spanless_eq_struct!(PolyTraitRef; bound_generic_params trait_ref span);
+spanless_eq_struct!(QSelf; ty path_span position);
+spanless_eq_struct!(Stmt; id kind span);
+spanless_eq_struct!(StrLit; style symbol suffix span symbol_unescaped);
+spanless_eq_struct!(StructField; attrs id span vis ident ty is_placeholder);
+spanless_eq_struct!(Token; kind span);
+spanless_eq_struct!(TraitRef; path ref_id);
+spanless_eq_struct!(Ty; id kind span);
+spanless_eq_struct!(UseTree; prefix kind span);
+spanless_eq_struct!(Variant; attrs id span vis ident data disr_expr is_placeholder);
+spanless_eq_struct!(WhereBoundPredicate; span bound_generic_params bounded_ty bounds);
+spanless_eq_struct!(WhereClause; predicates span);
+spanless_eq_struct!(WhereEqPredicate; id span lhs_ty rhs_ty);
+spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds);
+spanless_eq_enum!(AsmDialect; Att Intel);
+spanless_eq_enum!(AssocItemKind; Const(0 1) Fn(0 1) TyAlias(0 1) Macro(0));
+spanless_eq_enum!(AssocTyConstraintKind; Equality(ty) Bound(bounds));
+spanless_eq_enum!(AttrKind; Normal(0) DocComment(0));
+spanless_eq_enum!(AttrStyle; Outer Inner);
+spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt);
+spanless_eq_enum!(BindingMode; ByRef(0) ByValue(0));
+spanless_eq_enum!(BlockCheckMode; Default Unsafe(0));
+spanless_eq_enum!(BorrowKind; Ref Raw);
+spanless_eq_enum!(CaptureBy; Value Ref);
+spanless_eq_enum!(Constness; Const NotConst);
+spanless_eq_enum!(CrateSugar; PubCrate JustCrate);
+spanless_eq_enum!(Defaultness; Default Final);
+spanless_eq_enum!(Extern; None Implicit Explicit(0));
+spanless_eq_enum!(FloatTy; F32 F64);
+spanless_eq_enum!(ForeignItemKind; Fn(0 1) Static(0 1) Ty Macro(0));
+spanless_eq_enum!(FunctionRetTy; Default(0) Ty(0));
+spanless_eq_enum!(GenericArg; Lifetime(0) Type(0) Const(0));
+spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0));
+spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0));
+spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty));
+spanless_eq_enum!(ImplPolarity; Positive Negative);
+spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128);
+spanless_eq_enum!(IsAsync; Async(closure_id return_impl_trait_id) NotAsync);
+spanless_eq_enum!(IsAuto; Yes No);
+spanless_eq_enum!(LitFloatType; Suffixed(0) Unsuffixed);
+spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed);
+spanless_eq_enum!(MacArgs; Empty Delimited(0 1 2) Eq(0 1));
+spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace);
+spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces);
+spanless_eq_enum!(Movability; Static Movable);
+spanless_eq_enum!(Mutability; Mut Not);
+spanless_eq_enum!(RangeEnd; Included(0) Excluded);
+spanless_eq_enum!(RangeLimits; HalfOpen Closed);
+spanless_eq_enum!(StmtKind; Local(0) Item(0) Expr(0) Semi(0) Mac(0));
+spanless_eq_enum!(StrStyle; Cooked Raw(0));
+spanless_eq_enum!(TokenTree; Token(0) Delimited(0 1 2));
+spanless_eq_enum!(TraitBoundModifier; None Maybe);
+spanless_eq_enum!(TraitObjectSyntax; Dyn None);
+spanless_eq_enum!(UintTy; Usize U8 U16 U32 U64 U128);
+spanless_eq_enum!(UnOp; Deref Not Neg);
+spanless_eq_enum!(UnsafeSource; CompilerGenerated UserProvided);
+spanless_eq_enum!(Unsafety; Unsafe Normal);
+spanless_eq_enum!(UseTreeKind; Simple(0 1 2) Nested(0) Glob);
+spanless_eq_enum!(VariantData; Struct(0 1) Tuple(0 1) Unit(0));
+spanless_eq_enum!(VisibilityKind; Public Crate(0) Restricted(path id) Inherited);
+spanless_eq_enum!(WherePredicate; BoundPredicate(0) RegionPredicate(0) EqPredicate(0));
+spanless_eq_enum!(ExprKind; Box(0) Array(0) Call(0 1) MethodCall(0 1) Tup(0)
+ Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1) Let(0 1) If(0 1 2)
+ While(0 1 2) ForLoop(0 1 2 3) Loop(0 1) Match(0 1) Closure(0 1 2 3 4 5)
+ Block(0 1) Async(0 1 2) Await(0) TryBlock(0) Assign(0 1 2) AssignOp(0 1 2)
+ Field(0 1) Index(0 1) Range(0 1 2) Path(0 1) AddrOf(0 1 2) Break(0 1)
+ Continue(0) Ret(0) InlineAsm(0) Mac(0) Struct(0 1 2) Repeat(0 1) Paren(0)
+ Try(0) Yield(0) Err);
+spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1)
+ Fn(0 1 2) Mod(0) ForeignMod(0) GlobalAsm(0) TyAlias(0 1) Enum(0 1)
+ Struct(0 1) Union(0 1) Trait(0 1 2 3 4) TraitAlias(0 1) Impl(0 1 2 3 4 5 6)
+ Mac(0) MacroDef(0));
+spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0) Byte(0) Char(0) Int(0 1)
+ Float(0 1) Bool(0) Err(0));
+spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2) TupleStruct(0 1)
+ Or(0) Path(0 1) Tuple(0) Box(0) Ref(0 1) Lit(0) Range(0 1 2) Slice(0) Rest
+ Paren(0) Mac(0));
+spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Rptr(0 1) BareFn(0) Never
+ Tup(0) Path(0 1) TraitObject(0 1) ImplTrait(0 1) Paren(0) Typeof(0) Infer
+ ImplicitSelf Mac(0) Err CVarArgs);
+
+impl SpanlessEq for Ident {
+ fn eq(&self, other: &Self) -> bool {
+ self.as_str() == other.as_str()
+ }
+}
+
+// Give up on comparing literals inside of macros because there are so many
+// equivalent representations of the same literal; they are tested elsewhere
+impl SpanlessEq for token::Lit {
+ fn eq(&self, other: &Self) -> bool {
+ mem::discriminant(self) == mem::discriminant(other)
+ }
+}
+
+impl SpanlessEq for RangeSyntax {
+ fn eq(&self, _other: &Self) -> bool {
+ match self {
+ RangeSyntax::DotDotDot | RangeSyntax::DotDotEq => true,
+ }
+ }
+}
+
+impl SpanlessEq for TokenKind {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (TokenKind::Literal(this), TokenKind::Literal(other)) => SpanlessEq::eq(this, other),
+ (TokenKind::DotDotEq, _) | (TokenKind::DotDotDot, _) => match other {
+ TokenKind::DotDotEq | TokenKind::DotDotDot => true,
+ _ => false,
+ },
+ _ => self == other,
+ }
+ }
+}
+
+impl SpanlessEq for TokenStream {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&expand_tts(self), &expand_tts(other))
+ }
+}
+
+fn expand_tts(tts: &TokenStream) -> Vec<TokenTree> {
+ let mut tokens = Vec::new();
+ for tt in tts.clone().into_trees() {
+ let c = match tt {
+ TokenTree::Token(Token {
+ kind: TokenKind::DocComment(c),
+ ..
+ }) => c,
+ _ => {
+ tokens.push(tt);
+ continue;
+ }
+ };
+ let contents = comments::strip_doc_comment_decoration(&c.as_str());
+ let style = comments::doc_comment_style(&c.as_str());
+ tokens.push(TokenTree::token(TokenKind::Pound, DUMMY_SP));
+ if style == AttrStyle::Inner {
+ tokens.push(TokenTree::token(TokenKind::Not, DUMMY_SP));
+ }
+ let lit = token::Lit {
+ kind: token::LitKind::Str,
+ symbol: Symbol::intern(&contents),
+ suffix: None,
+ };
+ let tts = vec![
+ TokenTree::token(TokenKind::Ident(sym::doc, false), DUMMY_SP),
+ TokenTree::token(TokenKind::Eq, DUMMY_SP),
+ TokenTree::token(TokenKind::Literal(lit), DUMMY_SP),
+ ];
+ tokens.push(TokenTree::Delimited(
+ DelimSpan::dummy(),
+ DelimToken::Bracket,
+ tts.into_iter().collect::<TokenStream>().into(),
+ ));
+ }
+ tokens
+}
diff --git a/syn/tests/common/mod.rs b/syn/tests/common/mod.rs
new file mode 100644
index 0000000..3dd2552
--- /dev/null
+++ b/syn/tests/common/mod.rs
@@ -0,0 +1,19 @@
+#![allow(dead_code)]
+
+use std::env;
+
+pub mod eq;
+pub mod parse;
+
+/// Read the `ABORT_AFTER_FAILURE` environment variable, and parse it.
+pub fn abort_after() -> usize {
+ match env::var("ABORT_AFTER_FAILURE") {
+ Ok(s) => s.parse().expect("failed to parse ABORT_AFTER_FAILURE"),
+ Err(_) => usize::max_value(),
+ }
+}
+
+/// Are we running in travis-ci.org.
+pub fn travis_ci() -> bool {
+ env::var_os("TRAVIS").is_some()
+}
diff --git a/syn/tests/common/parse.rs b/syn/tests/common/parse.rs
new file mode 100644
index 0000000..fc3bb96
--- /dev/null
+++ b/syn/tests/common/parse.rs
@@ -0,0 +1,49 @@
+extern crate rustc_expand;
+extern crate rustc_parse as parse;
+extern crate rustc_span;
+extern crate syntax;
+
+use rustc_span::FileName;
+use syntax::ast;
+use syntax::ptr::P;
+use syntax::sess::ParseSess;
+use syntax::source_map::FilePathMapping;
+
+use std::panic;
+
+pub fn libsyntax_expr(input: &str) -> Option<P<ast::Expr>> {
+ match panic::catch_unwind(|| {
+ let sess = ParseSess::new(FilePathMapping::empty());
+ sess.span_diagnostic.set_continue_after_error(false);
+ let e = parse::new_parser_from_source_str(
+ &sess,
+ FileName::Custom("test_precedence".to_string()),
+ input.to_string(),
+ )
+ .parse_expr();
+ match e {
+ Ok(expr) => Some(expr),
+ Err(mut diagnostic) => {
+ diagnostic.emit();
+ None
+ }
+ }
+ }) {
+ Ok(Some(e)) => Some(e),
+ Ok(None) => None,
+ Err(_) => {
+ errorf!("libsyntax panicked\n");
+ None
+ }
+ }
+}
+
+pub fn syn_expr(input: &str) -> Option<syn::Expr> {
+ match syn::parse_str(input) {
+ Ok(e) => Some(e),
+ Err(msg) => {
+ errorf!("syn failed to parse\n{:?}\n", msg);
+ None
+ }
+ }
+}
diff --git a/syn/tests/debug/gen.rs b/syn/tests/debug/gen.rs
new file mode 100644
index 0000000..8450c09
--- /dev/null
+++ b/syn/tests/debug/gen.rs
@@ -0,0 +1,5633 @@
+// This file is @generated by syn-internal-codegen.
+// It is not intended for manual editing.
+
+use super::{Lite, RefCast};
+use std::fmt::{self, Debug};
+impl Debug for Lite<syn::Abi> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Abi");
+ if let Some(val) = &_val.name {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::LitStr);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("name", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::AngleBracketedGenericArguments> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("AngleBracketedGenericArguments");
+ if let Some(val) = &_val.colon2_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon2_token", Print::ref_cast(val));
+ }
+ if !_val.args.is_empty() {
+ formatter.field("args", Lite(&_val.args));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Arm> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Arm");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ if let Some(val) = &_val.guard {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::If, Box<syn::Expr>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("guard", Print::ref_cast(val));
+ }
+ formatter.field("body", Lite(&_val.body));
+ if let Some(val) = &_val.comma {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Comma);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("comma", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::AttrStyle> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::AttrStyle::Outer => formatter.write_str("Outer"),
+ syn::AttrStyle::Inner(_val) => {
+ formatter.write_str("Inner")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::Attribute> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Attribute");
+ formatter.field("style", Lite(&_val.style));
+ formatter.field("path", Lite(&_val.path));
+ formatter.field("tokens", Lite(&_val.tokens));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::BareFnArg> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("BareFnArg");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.name {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((proc_macro2::Ident, syn::token::Colon));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.0), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("name", Print::ref_cast(val));
+ }
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::BinOp> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::BinOp::Add(_val) => {
+ formatter.write_str("Add")?;
+ Ok(())
+ }
+ syn::BinOp::Sub(_val) => {
+ formatter.write_str("Sub")?;
+ Ok(())
+ }
+ syn::BinOp::Mul(_val) => {
+ formatter.write_str("Mul")?;
+ Ok(())
+ }
+ syn::BinOp::Div(_val) => {
+ formatter.write_str("Div")?;
+ Ok(())
+ }
+ syn::BinOp::Rem(_val) => {
+ formatter.write_str("Rem")?;
+ Ok(())
+ }
+ syn::BinOp::And(_val) => {
+ formatter.write_str("And")?;
+ Ok(())
+ }
+ syn::BinOp::Or(_val) => {
+ formatter.write_str("Or")?;
+ Ok(())
+ }
+ syn::BinOp::BitXor(_val) => {
+ formatter.write_str("BitXor")?;
+ Ok(())
+ }
+ syn::BinOp::BitAnd(_val) => {
+ formatter.write_str("BitAnd")?;
+ Ok(())
+ }
+ syn::BinOp::BitOr(_val) => {
+ formatter.write_str("BitOr")?;
+ Ok(())
+ }
+ syn::BinOp::Shl(_val) => {
+ formatter.write_str("Shl")?;
+ Ok(())
+ }
+ syn::BinOp::Shr(_val) => {
+ formatter.write_str("Shr")?;
+ Ok(())
+ }
+ syn::BinOp::Eq(_val) => {
+ formatter.write_str("Eq")?;
+ Ok(())
+ }
+ syn::BinOp::Lt(_val) => {
+ formatter.write_str("Lt")?;
+ Ok(())
+ }
+ syn::BinOp::Le(_val) => {
+ formatter.write_str("Le")?;
+ Ok(())
+ }
+ syn::BinOp::Ne(_val) => {
+ formatter.write_str("Ne")?;
+ Ok(())
+ }
+ syn::BinOp::Ge(_val) => {
+ formatter.write_str("Ge")?;
+ Ok(())
+ }
+ syn::BinOp::Gt(_val) => {
+ formatter.write_str("Gt")?;
+ Ok(())
+ }
+ syn::BinOp::AddEq(_val) => {
+ formatter.write_str("AddEq")?;
+ Ok(())
+ }
+ syn::BinOp::SubEq(_val) => {
+ formatter.write_str("SubEq")?;
+ Ok(())
+ }
+ syn::BinOp::MulEq(_val) => {
+ formatter.write_str("MulEq")?;
+ Ok(())
+ }
+ syn::BinOp::DivEq(_val) => {
+ formatter.write_str("DivEq")?;
+ Ok(())
+ }
+ syn::BinOp::RemEq(_val) => {
+ formatter.write_str("RemEq")?;
+ Ok(())
+ }
+ syn::BinOp::BitXorEq(_val) => {
+ formatter.write_str("BitXorEq")?;
+ Ok(())
+ }
+ syn::BinOp::BitAndEq(_val) => {
+ formatter.write_str("BitAndEq")?;
+ Ok(())
+ }
+ syn::BinOp::BitOrEq(_val) => {
+ formatter.write_str("BitOrEq")?;
+ Ok(())
+ }
+ syn::BinOp::ShlEq(_val) => {
+ formatter.write_str("ShlEq")?;
+ Ok(())
+ }
+ syn::BinOp::ShrEq(_val) => {
+ formatter.write_str("ShrEq")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::Binding> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Binding");
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Block> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Block");
+ if !_val.stmts.is_empty() {
+ formatter.field("stmts", Lite(&_val.stmts));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::BoundLifetimes> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("BoundLifetimes");
+ if !_val.lifetimes.is_empty() {
+ formatter.field("lifetimes", Lite(&_val.lifetimes));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ConstParam> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ConstParam");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ if let Some(val) = &_val.eq_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Eq);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("eq_token", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.default {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Expr);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("default", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Constraint> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Constraint");
+ formatter.field("ident", Lite(&_val.ident));
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Data> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Data::Struct(_val) => {
+ let mut formatter = formatter.debug_struct("Data::Struct");
+ formatter.field("fields", Lite(&_val.fields));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Data::Enum(_val) => {
+ let mut formatter = formatter.debug_struct("Data::Enum");
+ if !_val.variants.is_empty() {
+ formatter.field("variants", Lite(&_val.variants));
+ }
+ formatter.finish()
+ }
+ syn::Data::Union(_val) => {
+ let mut formatter = formatter.debug_struct("Data::Union");
+ formatter.field("fields", Lite(&_val.fields));
+ formatter.finish()
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::DataEnum> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("DataEnum");
+ if !_val.variants.is_empty() {
+ formatter.field("variants", Lite(&_val.variants));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::DataStruct> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("DataStruct");
+ formatter.field("fields", Lite(&_val.fields));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::DataUnion> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("DataUnion");
+ formatter.field("fields", Lite(&_val.fields));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::DeriveInput> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("DeriveInput");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("data", Lite(&_val.data));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Expr> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Expr::Array(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Array");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Assign(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Assign");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("left", Lite(&_val.left));
+ formatter.field("right", Lite(&_val.right));
+ formatter.finish()
+ }
+ syn::Expr::AssignOp(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::AssignOp");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("left", Lite(&_val.left));
+ formatter.field("op", Lite(&_val.op));
+ formatter.field("right", Lite(&_val.right));
+ formatter.finish()
+ }
+ syn::Expr::Async(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Async");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.capture {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Move);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("capture", Print::ref_cast(val));
+ }
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+ syn::Expr::Await(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Await");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("base", Lite(&_val.base));
+ formatter.finish()
+ }
+ syn::Expr::Binary(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Binary");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("left", Lite(&_val.left));
+ formatter.field("op", Lite(&_val.op));
+ formatter.field("right", Lite(&_val.right));
+ formatter.finish()
+ }
+ syn::Expr::Block(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Block");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Label);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+ syn::Expr::Box(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Box");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Expr::Break(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Break");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Lifetime);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.expr {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("expr", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Call(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Call");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("func", Lite(&_val.func));
+ if !_val.args.is_empty() {
+ formatter.field("args", Lite(&_val.args));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Cast(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Cast");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+ syn::Expr::Closure(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Closure");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.asyncness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Async);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("asyncness", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.movability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Static);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("movability", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.capture {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Move);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("capture", Print::ref_cast(val));
+ }
+ if !_val.inputs.is_empty() {
+ formatter.field("inputs", Lite(&_val.inputs));
+ }
+ formatter.field("output", Lite(&_val.output));
+ formatter.field("body", Lite(&_val.body));
+ formatter.finish()
+ }
+ syn::Expr::Continue(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Continue");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Lifetime);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Field(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Field");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("base", Lite(&_val.base));
+ formatter.field("member", Lite(&_val.member));
+ formatter.finish()
+ }
+ syn::Expr::ForLoop(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::ForLoop");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Label);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("body", Lite(&_val.body));
+ formatter.finish()
+ }
+ syn::Expr::Group(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Group");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Expr::If(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::If");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("cond", Lite(&_val.cond));
+ formatter.field("then_branch", Lite(&_val.then_branch));
+ if let Some(val) = &_val.else_branch {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Else, Box<syn::Expr>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("else_branch", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Index(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Index");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("index", Lite(&_val.index));
+ formatter.finish()
+ }
+ syn::Expr::Let(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Let");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Expr::Lit(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Lit");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("lit", Lite(&_val.lit));
+ formatter.finish()
+ }
+ syn::Expr::Loop(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Loop");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Label);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.field("body", Lite(&_val.body));
+ formatter.finish()
+ }
+ syn::Expr::Macro(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Macro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ formatter.finish()
+ }
+ syn::Expr::Match(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Match");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ if !_val.arms.is_empty() {
+ formatter.field("arms", Lite(&_val.arms));
+ }
+ formatter.finish()
+ }
+ syn::Expr::MethodCall(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::MethodCall");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("receiver", Lite(&_val.receiver));
+ formatter.field("method", Lite(&_val.method));
+ if let Some(val) = &_val.turbofish {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::MethodTurbofish);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("turbofish", Print::ref_cast(val));
+ }
+ if !_val.args.is_empty() {
+ formatter.field("args", Lite(&_val.args));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Paren(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Paren");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Expr::Path(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Path");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.qself {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::QSelf);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("qself", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+ syn::Expr::Range(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Range");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.from {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("from", Print::ref_cast(val));
+ }
+ formatter.field("limits", Lite(&_val.limits));
+ if let Some(val) = &_val.to {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("to", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Reference(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Reference");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Expr::Repeat(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Repeat");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("len", Lite(&_val.len));
+ formatter.finish()
+ }
+ syn::Expr::Return(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Return");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.expr {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("expr", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Struct(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Struct");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("path", Lite(&_val.path));
+ if !_val.fields.is_empty() {
+ formatter.field("fields", Lite(&_val.fields));
+ }
+ if let Some(val) = &_val.dot2_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Dot2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("dot2_token", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.rest {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("rest", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Try(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Try");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Expr::TryBlock(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::TryBlock");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+ syn::Expr::Tuple(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Tuple");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+ syn::Expr::Type(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Type");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+ syn::Expr::Unary(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Unary");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("op", Lite(&_val.op));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Expr::Unsafe(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Unsafe");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+ syn::Expr::Verbatim(_val) => {
+ formatter.write_str("Verbatim")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::Expr::While(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::While");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Label);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.field("cond", Lite(&_val.cond));
+ formatter.field("body", Lite(&_val.body));
+ formatter.finish()
+ }
+ syn::Expr::Yield(_val) => {
+ let mut formatter = formatter.debug_struct("Expr::Yield");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.expr {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("expr", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+impl Debug for Lite<syn::ExprArray> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprArray");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprAssign> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprAssign");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("left", Lite(&_val.left));
+ formatter.field("right", Lite(&_val.right));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprAssignOp> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprAssignOp");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("left", Lite(&_val.left));
+ formatter.field("op", Lite(&_val.op));
+ formatter.field("right", Lite(&_val.right));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprAsync> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprAsync");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.capture {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Move);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("capture", Print::ref_cast(val));
+ }
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprAwait> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprAwait");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("base", Lite(&_val.base));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprBinary> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprBinary");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("left", Lite(&_val.left));
+ formatter.field("op", Lite(&_val.op));
+ formatter.field("right", Lite(&_val.right));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprBlock> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprBlock");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Label);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprBox> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprBox");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprBreak> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprBreak");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Lifetime);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.expr {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("expr", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprCall> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprCall");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("func", Lite(&_val.func));
+ if !_val.args.is_empty() {
+ formatter.field("args", Lite(&_val.args));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprCast> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprCast");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprClosure> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprClosure");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.asyncness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Async);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("asyncness", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.movability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Static);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("movability", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.capture {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Move);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("capture", Print::ref_cast(val));
+ }
+ if !_val.inputs.is_empty() {
+ formatter.field("inputs", Lite(&_val.inputs));
+ }
+ formatter.field("output", Lite(&_val.output));
+ formatter.field("body", Lite(&_val.body));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprContinue> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprContinue");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Lifetime);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprField> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprField");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("base", Lite(&_val.base));
+ formatter.field("member", Lite(&_val.member));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprForLoop> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprForLoop");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Label);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("body", Lite(&_val.body));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprGroup> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprGroup");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprIf> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprIf");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("cond", Lite(&_val.cond));
+ formatter.field("then_branch", Lite(&_val.then_branch));
+ if let Some(val) = &_val.else_branch {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Else, Box<syn::Expr>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("else_branch", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprIndex> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprIndex");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("index", Lite(&_val.index));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprLet> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprLet");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprLit> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprLit");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("lit", Lite(&_val.lit));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprLoop> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprLoop");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Label);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.field("body", Lite(&_val.body));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprMacro> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprMacro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprMatch> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprMatch");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ if !_val.arms.is_empty() {
+ formatter.field("arms", Lite(&_val.arms));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprMethodCall> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprMethodCall");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("receiver", Lite(&_val.receiver));
+ formatter.field("method", Lite(&_val.method));
+ if let Some(val) = &_val.turbofish {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::MethodTurbofish);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("turbofish", Print::ref_cast(val));
+ }
+ if !_val.args.is_empty() {
+ formatter.field("args", Lite(&_val.args));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprParen> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprParen");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprPath> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprPath");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.qself {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::QSelf);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("qself", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprRange> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprRange");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.from {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("from", Print::ref_cast(val));
+ }
+ formatter.field("limits", Lite(&_val.limits));
+ if let Some(val) = &_val.to {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("to", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprReference> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprReference");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprRepeat> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprRepeat");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("len", Lite(&_val.len));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprReturn> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprReturn");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.expr {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("expr", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprStruct> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprStruct");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("path", Lite(&_val.path));
+ if !_val.fields.is_empty() {
+ formatter.field("fields", Lite(&_val.fields));
+ }
+ if let Some(val) = &_val.dot2_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Dot2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("dot2_token", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.rest {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("rest", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprTry> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprTry");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprTryBlock> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprTryBlock");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprTuple> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprTuple");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprType> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprType");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprUnary> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprUnary");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("op", Lite(&_val.op));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprUnsafe> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprUnsafe");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprWhile> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprWhile");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.label {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Label);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("label", Print::ref_cast(val));
+ }
+ formatter.field("cond", Lite(&_val.cond));
+ formatter.field("body", Lite(&_val.body));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ExprYield> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ExprYield");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.expr {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Box<syn::Expr>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("expr", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Field> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Field");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.ident {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(proc_macro2::Ident);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("ident", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::FieldPat> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("FieldPat");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("member", Lite(&_val.member));
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::FieldValue> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("FieldValue");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("member", Lite(&_val.member));
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Fields> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Fields::Named(_val) => {
+ let mut formatter = formatter.debug_struct("Fields::Named");
+ if !_val.named.is_empty() {
+ formatter.field("named", Lite(&_val.named));
+ }
+ formatter.finish()
+ }
+ syn::Fields::Unnamed(_val) => {
+ let mut formatter = formatter.debug_struct("Fields::Unnamed");
+ if !_val.unnamed.is_empty() {
+ formatter.field("unnamed", Lite(&_val.unnamed));
+ }
+ formatter.finish()
+ }
+ syn::Fields::Unit => formatter.write_str("Unit"),
+ }
+ }
+}
+impl Debug for Lite<syn::FieldsNamed> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("FieldsNamed");
+ if !_val.named.is_empty() {
+ formatter.field("named", Lite(&_val.named));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::FieldsUnnamed> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("FieldsUnnamed");
+ if !_val.unnamed.is_empty() {
+ formatter.field("unnamed", Lite(&_val.unnamed));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::File> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("File");
+ if let Some(val) = &_val.shebang {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(String);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("shebang", Print::ref_cast(val));
+ }
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.items.is_empty() {
+ formatter.field("items", Lite(&_val.items));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::FnArg> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::FnArg::Receiver(_val) => {
+ formatter.write_str("Receiver")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::FnArg::Typed(_val) => {
+ formatter.write_str("Typed")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::ForeignItem> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::ForeignItem::Fn(_val) => {
+ let mut formatter = formatter.debug_struct("ForeignItem::Fn");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("sig", Lite(&_val.sig));
+ formatter.finish()
+ }
+ syn::ForeignItem::Static(_val) => {
+ let mut formatter = formatter.debug_struct("ForeignItem::Static");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+ syn::ForeignItem::Type(_val) => {
+ let mut formatter = formatter.debug_struct("ForeignItem::Type");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.finish()
+ }
+ syn::ForeignItem::Macro(_val) => {
+ let mut formatter = formatter.debug_struct("ForeignItem::Macro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::ForeignItem::Verbatim(_val) => {
+ formatter.write_str("Verbatim")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+impl Debug for Lite<syn::ForeignItemFn> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ForeignItemFn");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("sig", Lite(&_val.sig));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ForeignItemMacro> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ForeignItemMacro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ForeignItemStatic> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ForeignItemStatic");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ForeignItemType> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ForeignItemType");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::GenericArgument> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::GenericArgument::Lifetime(_val) => {
+ formatter.write_str("Lifetime")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::GenericArgument::Type(_val) => {
+ formatter.write_str("Type")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::GenericArgument::Binding(_val) => {
+ formatter.write_str("Binding")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::GenericArgument::Constraint(_val) => {
+ formatter.write_str("Constraint")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::GenericArgument::Const(_val) => {
+ formatter.write_str("Const")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::GenericMethodArgument> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::GenericMethodArgument::Type(_val) => {
+ formatter.write_str("Type")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::GenericMethodArgument::Const(_val) => {
+ formatter.write_str("Const")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::GenericParam> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::GenericParam::Type(_val) => {
+ formatter.write_str("Type")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::GenericParam::Lifetime(_val) => {
+ formatter.write_str("Lifetime")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::GenericParam::Const(_val) => {
+ formatter.write_str("Const")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::Generics> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Generics");
+ if let Some(val) = &_val.lt_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Lt);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("lt_token", Print::ref_cast(val));
+ }
+ if !_val.params.is_empty() {
+ formatter.field("params", Lite(&_val.params));
+ }
+ if let Some(val) = &_val.gt_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Gt);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("gt_token", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.where_clause {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::WhereClause);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("where_clause", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ImplItem> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::ImplItem::Const(_val) => {
+ let mut formatter = formatter.debug_struct("ImplItem::Const");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.defaultness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Default);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("defaultness", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::ImplItem::Method(_val) => {
+ let mut formatter = formatter.debug_struct("ImplItem::Method");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.defaultness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Default);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("defaultness", Print::ref_cast(val));
+ }
+ formatter.field("sig", Lite(&_val.sig));
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+ syn::ImplItem::Type(_val) => {
+ let mut formatter = formatter.debug_struct("ImplItem::Type");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.defaultness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Default);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("defaultness", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+ syn::ImplItem::Macro(_val) => {
+ let mut formatter = formatter.debug_struct("ImplItem::Macro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::ImplItem::Verbatim(_val) => {
+ formatter.write_str("Verbatim")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+impl Debug for Lite<syn::ImplItemConst> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ImplItemConst");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.defaultness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Default);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("defaultness", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ImplItemMacro> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ImplItemMacro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ImplItemMethod> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ImplItemMethod");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.defaultness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Default);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("defaultness", Print::ref_cast(val));
+ }
+ formatter.field("sig", Lite(&_val.sig));
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ImplItemType> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ImplItemType");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.defaultness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Default);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("defaultness", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Index> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Index");
+ formatter.field("index", Lite(&_val.index));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Item> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Item::Const(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Const");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Item::Enum(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Enum");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if !_val.variants.is_empty() {
+ formatter.field("variants", Lite(&_val.variants));
+ }
+ formatter.finish()
+ }
+ syn::Item::ExternCrate(_val) => {
+ let mut formatter = formatter.debug_struct("Item::ExternCrate");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ if let Some(val) = &_val.rename {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::As, proc_macro2::Ident));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("rename", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Item::Fn(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Fn");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("sig", Lite(&_val.sig));
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+ syn::Item::ForeignMod(_val) => {
+ let mut formatter = formatter.debug_struct("Item::ForeignMod");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("abi", Lite(&_val.abi));
+ if !_val.items.is_empty() {
+ formatter.field("items", Lite(&_val.items));
+ }
+ formatter.finish()
+ }
+ syn::Item::Impl(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Impl");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.defaultness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Default);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("defaultness", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.unsafety {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Unsafe);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("unsafety", Print::ref_cast(val));
+ }
+ formatter.field("generics", Lite(&_val.generics));
+ if let Some(val) = &_val.trait_ {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((Option<syn::token::Bang>, syn::Path, syn::token::For));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(
+ &(
+ {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Option<syn::token::Bang>);
+ impl Debug for Print {
+ fn fmt(
+ &self,
+ formatter: &mut fmt::Formatter,
+ ) -> fmt::Result
+ {
+ match &self.0 {
+ Some(_val) => {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ None => formatter.write_str("None"),
+ }
+ }
+ }
+ Print::ref_cast(&_val.0)
+ },
+ Lite(&_val.1),
+ ),
+ formatter,
+ )?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("trait_", Print::ref_cast(val));
+ }
+ formatter.field("self_ty", Lite(&_val.self_ty));
+ if !_val.items.is_empty() {
+ formatter.field("items", Lite(&_val.items));
+ }
+ formatter.finish()
+ }
+ syn::Item::Macro(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Macro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.ident {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(proc_macro2::Ident);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("ident", Print::ref_cast(val));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Item::Macro2(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Macro2");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("rules", Lite(&_val.rules));
+ formatter.finish()
+ }
+ syn::Item::Mod(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Mod");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ if let Some(val) = &_val.content {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Brace, Vec<syn::Item>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("content", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.semi {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Item::Static(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Static");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Item::Struct(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Struct");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("fields", Lite(&_val.fields));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Item::Trait(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Trait");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.unsafety {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Unsafe);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("unsafety", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.auto_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Auto);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("auto_token", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ if !_val.supertraits.is_empty() {
+ formatter.field("supertraits", Lite(&_val.supertraits));
+ }
+ if !_val.items.is_empty() {
+ formatter.field("items", Lite(&_val.items));
+ }
+ formatter.finish()
+ }
+ syn::Item::TraitAlias(_val) => {
+ let mut formatter = formatter.debug_struct("Item::TraitAlias");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+ syn::Item::Type(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Type");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+ syn::Item::Union(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Union");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("fields", Lite(&_val.fields));
+ formatter.finish()
+ }
+ syn::Item::Use(_val) => {
+ let mut formatter = formatter.debug_struct("Item::Use");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.leading_colon {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("leading_colon", Print::ref_cast(val));
+ }
+ formatter.field("tree", Lite(&_val.tree));
+ formatter.finish()
+ }
+ syn::Item::Verbatim(_val) => {
+ formatter.write_str("Verbatim")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+impl Debug for Lite<syn::ItemConst> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemConst");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemEnum> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemEnum");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if !_val.variants.is_empty() {
+ formatter.field("variants", Lite(&_val.variants));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemExternCrate> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemExternCrate");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ if let Some(val) = &_val.rename {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::As, proc_macro2::Ident));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("rename", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemFn> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemFn");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("sig", Lite(&_val.sig));
+ formatter.field("block", Lite(&_val.block));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemForeignMod> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemForeignMod");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("abi", Lite(&_val.abi));
+ if !_val.items.is_empty() {
+ formatter.field("items", Lite(&_val.items));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemImpl> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemImpl");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.defaultness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Default);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("defaultness", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.unsafety {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Unsafe);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("unsafety", Print::ref_cast(val));
+ }
+ formatter.field("generics", Lite(&_val.generics));
+ if let Some(val) = &_val.trait_ {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((Option<syn::token::Bang>, syn::Path, syn::token::For));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(
+ &(
+ {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Option<syn::token::Bang>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match &self.0 {
+ Some(_val) => {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ None => formatter.write_str("None"),
+ }
+ }
+ }
+ Print::ref_cast(&_val.0)
+ },
+ Lite(&_val.1),
+ ),
+ formatter,
+ )?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("trait_", Print::ref_cast(val));
+ }
+ formatter.field("self_ty", Lite(&_val.self_ty));
+ if !_val.items.is_empty() {
+ formatter.field("items", Lite(&_val.items));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemMacro> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemMacro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.ident {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(proc_macro2::Ident);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("ident", Print::ref_cast(val));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemMacro2> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemMacro2");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("rules", Lite(&_val.rules));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemMod> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemMod");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ if let Some(val) = &_val.content {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Brace, Vec<syn::Item>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("content", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.semi {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemStatic> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemStatic");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemStruct> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemStruct");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("fields", Lite(&_val.fields));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemTrait> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemTrait");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.unsafety {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Unsafe);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("unsafety", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.auto_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Auto);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("auto_token", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ if !_val.supertraits.is_empty() {
+ formatter.field("supertraits", Lite(&_val.supertraits));
+ }
+ if !_val.items.is_empty() {
+ formatter.field("items", Lite(&_val.items));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemTraitAlias> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemTraitAlias");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemType> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemType");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemUnion> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemUnion");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ formatter.field("fields", Lite(&_val.fields));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ItemUse> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ItemUse");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("vis", Lite(&_val.vis));
+ if let Some(val) = &_val.leading_colon {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("leading_colon", Print::ref_cast(val));
+ }
+ formatter.field("tree", Lite(&_val.tree));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Label> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Label");
+ formatter.field("name", Lite(&_val.name));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Lifetime> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Lifetime");
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::LifetimeDef> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("LifetimeDef");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("lifetime", Lite(&_val.lifetime));
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Lit> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Lit::Str(_val) => write!(formatter, "{:?}", _val.value()),
+ syn::Lit::ByteStr(_val) => write!(formatter, "{:?}", _val.value()),
+ syn::Lit::Byte(_val) => write!(formatter, "{:?}", _val.value()),
+ syn::Lit::Char(_val) => write!(formatter, "{:?}", _val.value()),
+ syn::Lit::Int(_val) => write!(formatter, "{}", _val),
+ syn::Lit::Float(_val) => write!(formatter, "{}", _val),
+ syn::Lit::Bool(_val) => {
+ let mut formatter = formatter.debug_struct("Lit::Bool");
+ formatter.field("value", Lite(&_val.value));
+ formatter.finish()
+ }
+ syn::Lit::Verbatim(_val) => {
+ formatter.write_str("Verbatim")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::LitBool> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("LitBool");
+ formatter.field("value", Lite(&_val.value));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::LitByte> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ write!(formatter, "{:?}", _val.value())
+ }
+}
+impl Debug for Lite<syn::LitByteStr> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ write!(formatter, "{:?}", _val.value())
+ }
+}
+impl Debug for Lite<syn::LitChar> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ write!(formatter, "{:?}", _val.value())
+ }
+}
+impl Debug for Lite<syn::LitFloat> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ write!(formatter, "{}", _val)
+ }
+}
+impl Debug for Lite<syn::LitInt> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ write!(formatter, "{}", _val)
+ }
+}
+impl Debug for Lite<syn::LitStr> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ write!(formatter, "{:?}", _val.value())
+ }
+}
+impl Debug for Lite<syn::Local> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Local");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ if let Some(val) = &_val.init {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Eq, Box<syn::Expr>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("init", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Macro> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Macro");
+ formatter.field("path", Lite(&_val.path));
+ formatter.field("delimiter", Lite(&_val.delimiter));
+ formatter.field("tokens", Lite(&_val.tokens));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::MacroDelimiter> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::MacroDelimiter::Paren(_val) => {
+ formatter.write_str("Paren")?;
+ Ok(())
+ }
+ syn::MacroDelimiter::Brace(_val) => {
+ formatter.write_str("Brace")?;
+ Ok(())
+ }
+ syn::MacroDelimiter::Bracket(_val) => {
+ formatter.write_str("Bracket")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::Member> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Member::Named(_val) => {
+ formatter.write_str("Named")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::Member::Unnamed(_val) => {
+ formatter.write_str("Unnamed")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::Meta> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Meta::Path(_val) => {
+ formatter.write_str("Path")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::Meta::List(_val) => {
+ let mut formatter = formatter.debug_struct("Meta::List");
+ formatter.field("path", Lite(&_val.path));
+ if !_val.nested.is_empty() {
+ formatter.field("nested", Lite(&_val.nested));
+ }
+ formatter.finish()
+ }
+ syn::Meta::NameValue(_val) => {
+ let mut formatter = formatter.debug_struct("Meta::NameValue");
+ formatter.field("path", Lite(&_val.path));
+ formatter.field("lit", Lite(&_val.lit));
+ formatter.finish()
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::MetaList> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("MetaList");
+ formatter.field("path", Lite(&_val.path));
+ if !_val.nested.is_empty() {
+ formatter.field("nested", Lite(&_val.nested));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::MetaNameValue> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("MetaNameValue");
+ formatter.field("path", Lite(&_val.path));
+ formatter.field("lit", Lite(&_val.lit));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::MethodTurbofish> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("MethodTurbofish");
+ if !_val.args.is_empty() {
+ formatter.field("args", Lite(&_val.args));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::NestedMeta> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::NestedMeta::Meta(_val) => {
+ formatter.write_str("Meta")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::NestedMeta::Lit(_val) => {
+ formatter.write_str("Lit")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::ParenthesizedGenericArguments> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("ParenthesizedGenericArguments");
+ if !_val.inputs.is_empty() {
+ formatter.field("inputs", Lite(&_val.inputs));
+ }
+ formatter.field("output", Lite(&_val.output));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Pat> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Pat::Box(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Box");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.finish()
+ }
+ syn::Pat::Ident(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Ident");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.by_ref {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Ref);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("by_ref", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ if let Some(val) = &_val.subpat {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::At, Box<syn::Pat>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("subpat", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Pat::Lit(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Lit");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+ syn::Pat::Macro(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Macro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ formatter.finish()
+ }
+ syn::Pat::Or(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Or");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.leading_vert {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Or);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("leading_vert", Print::ref_cast(val));
+ }
+ if !_val.cases.is_empty() {
+ formatter.field("cases", Lite(&_val.cases));
+ }
+ formatter.finish()
+ }
+ syn::Pat::Path(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Path");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.qself {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::QSelf);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("qself", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+ syn::Pat::Range(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Range");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("lo", Lite(&_val.lo));
+ formatter.field("limits", Lite(&_val.limits));
+ formatter.field("hi", Lite(&_val.hi));
+ formatter.finish()
+ }
+ syn::Pat::Reference(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Reference");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.finish()
+ }
+ syn::Pat::Rest(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Rest");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.finish()
+ }
+ syn::Pat::Slice(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Slice");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+ syn::Pat::Struct(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Struct");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("path", Lite(&_val.path));
+ if !_val.fields.is_empty() {
+ formatter.field("fields", Lite(&_val.fields));
+ }
+ if let Some(val) = &_val.dot2_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Dot2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("dot2_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::Pat::Tuple(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Tuple");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+ syn::Pat::TupleStruct(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::TupleStruct");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.finish()
+ }
+ syn::Pat::Type(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Type");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+ syn::Pat::Verbatim(_val) => {
+ formatter.write_str("Verbatim")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::Pat::Wild(_val) => {
+ let mut formatter = formatter.debug_struct("Pat::Wild");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.finish()
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+impl Debug for Lite<syn::PatBox> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatBox");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatIdent> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatIdent");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.by_ref {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Ref);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("by_ref", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ if let Some(val) = &_val.subpat {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::At, Box<syn::Pat>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("subpat", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatLit> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatLit");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("expr", Lite(&_val.expr));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatMacro> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatMacro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatOr> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatOr");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.leading_vert {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Or);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("leading_vert", Print::ref_cast(val));
+ }
+ if !_val.cases.is_empty() {
+ formatter.field("cases", Lite(&_val.cases));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatPath> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatPath");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.qself {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::QSelf);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("qself", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatRange> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatRange");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("lo", Lite(&_val.lo));
+ formatter.field("limits", Lite(&_val.limits));
+ formatter.field("hi", Lite(&_val.hi));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatReference> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatReference");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatRest> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatRest");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatSlice> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatSlice");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatStruct> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatStruct");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("path", Lite(&_val.path));
+ if !_val.fields.is_empty() {
+ formatter.field("fields", Lite(&_val.fields));
+ }
+ if let Some(val) = &_val.dot2_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Dot2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("dot2_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatTuple> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatTuple");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatTupleStruct> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatTupleStruct");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatType> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatType");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("pat", Lite(&_val.pat));
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PatWild> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PatWild");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Path> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Path");
+ if let Some(val) = &_val.leading_colon {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("leading_colon", Print::ref_cast(val));
+ }
+ if !_val.segments.is_empty() {
+ formatter.field("segments", Lite(&_val.segments));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PathArguments> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::PathArguments::None => formatter.write_str("None"),
+ syn::PathArguments::AngleBracketed(_val) => {
+ let mut formatter = formatter.debug_struct("PathArguments::AngleBracketed");
+ if let Some(val) = &_val.colon2_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon2);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon2_token", Print::ref_cast(val));
+ }
+ if !_val.args.is_empty() {
+ formatter.field("args", Lite(&_val.args));
+ }
+ formatter.finish()
+ }
+ syn::PathArguments::Parenthesized(_val) => {
+ let mut formatter = formatter.debug_struct("PathArguments::Parenthesized");
+ if !_val.inputs.is_empty() {
+ formatter.field("inputs", Lite(&_val.inputs));
+ }
+ formatter.field("output", Lite(&_val.output));
+ formatter.finish()
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::PathSegment> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PathSegment");
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("arguments", Lite(&_val.arguments));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PredicateEq> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PredicateEq");
+ formatter.field("lhs_ty", Lite(&_val.lhs_ty));
+ formatter.field("rhs_ty", Lite(&_val.rhs_ty));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PredicateLifetime> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PredicateLifetime");
+ formatter.field("lifetime", Lite(&_val.lifetime));
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::PredicateType> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("PredicateType");
+ if let Some(val) = &_val.lifetimes {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::BoundLifetimes);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("lifetimes", Print::ref_cast(val));
+ }
+ formatter.field("bounded_ty", Lite(&_val.bounded_ty));
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::QSelf> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("QSelf");
+ formatter.field("ty", Lite(&_val.ty));
+ formatter.field("position", Lite(&_val.position));
+ if let Some(val) = &_val.as_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::As);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("as_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::RangeLimits> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::RangeLimits::HalfOpen(_val) => {
+ formatter.write_str("HalfOpen")?;
+ Ok(())
+ }
+ syn::RangeLimits::Closed(_val) => {
+ formatter.write_str("Closed")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::Receiver> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Receiver");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ if let Some(val) = &_val.reference {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::And, Option<syn::Lifetime>));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(
+ {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(Option<syn::Lifetime>);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match &self.0 {
+ Some(_val) => {
+ formatter.write_str("Some")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ None => formatter.write_str("None"),
+ }
+ }
+ }
+ Print::ref_cast(&_val.1)
+ },
+ formatter,
+ )?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("reference", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::ReturnType> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::ReturnType::Default => formatter.write_str("Default"),
+ syn::ReturnType::Type(_v0, _v1) => {
+ let mut formatter = formatter.debug_tuple("Type");
+ formatter.field(Lite(_v1));
+ formatter.finish()
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::Signature> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Signature");
+ if let Some(val) = &_val.constness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Const);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("constness", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.asyncness {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Async);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("asyncness", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.unsafety {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Unsafe);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("unsafety", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.abi {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Abi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("abi", Print::ref_cast(val));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if !_val.inputs.is_empty() {
+ formatter.field("inputs", Lite(&_val.inputs));
+ }
+ if let Some(val) = &_val.variadic {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Variadic);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("variadic", Print::ref_cast(val));
+ }
+ formatter.field("output", Lite(&_val.output));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Stmt> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Stmt::Local(_val) => {
+ formatter.write_str("Local")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::Stmt::Item(_val) => {
+ formatter.write_str("Item")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::Stmt::Expr(_val) => {
+ formatter.write_str("Expr")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::Stmt::Semi(_v0, _v1) => {
+ let mut formatter = formatter.debug_tuple("Semi");
+ formatter.field(Lite(_v0));
+ formatter.finish()
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::TraitBound> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TraitBound");
+ if let Some(val) = &_val.paren_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Paren);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("paren_token", Print::ref_cast(val));
+ }
+ formatter.field("modifier", Lite(&_val.modifier));
+ if let Some(val) = &_val.lifetimes {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::BoundLifetimes);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("lifetimes", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TraitBoundModifier> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::TraitBoundModifier::None => formatter.write_str("None"),
+ syn::TraitBoundModifier::Maybe(_val) => {
+ formatter.write_str("Maybe")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::TraitItem> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::TraitItem::Const(_val) => {
+ let mut formatter = formatter.debug_struct("TraitItem::Const");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ if let Some(val) = &_val.default {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Eq, syn::Expr));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("default", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::TraitItem::Method(_val) => {
+ let mut formatter = formatter.debug_struct("TraitItem::Method");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("sig", Lite(&_val.sig));
+ if let Some(val) = &_val.default {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Block);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("default", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::TraitItem::Type(_val) => {
+ let mut formatter = formatter.debug_struct("TraitItem::Type");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ if let Some(val) = &_val.default {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Eq, syn::Type));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("default", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::TraitItem::Macro(_val) => {
+ let mut formatter = formatter.debug_struct("TraitItem::Macro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+ syn::TraitItem::Verbatim(_val) => {
+ formatter.write_str("Verbatim")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+impl Debug for Lite<syn::TraitItemConst> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TraitItemConst");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("ty", Lite(&_val.ty));
+ if let Some(val) = &_val.default {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Eq, syn::Expr));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("default", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TraitItemMacro> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TraitItemMacro");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("mac", Lite(&_val.mac));
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TraitItemMethod> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TraitItemMethod");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("sig", Lite(&_val.sig));
+ if let Some(val) = &_val.default {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Block);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("default", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.semi_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Semi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("semi_token", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TraitItemType> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TraitItemType");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("generics", Lite(&_val.generics));
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ if let Some(val) = &_val.default {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Eq, syn::Type));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("default", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Type> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Type::Array(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Array");
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.field("len", Lite(&_val.len));
+ formatter.finish()
+ }
+ syn::Type::BareFn(_val) => {
+ let mut formatter = formatter.debug_struct("Type::BareFn");
+ if let Some(val) = &_val.lifetimes {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::BoundLifetimes);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("lifetimes", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.unsafety {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Unsafe);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("unsafety", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.abi {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Abi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("abi", Print::ref_cast(val));
+ }
+ if !_val.inputs.is_empty() {
+ formatter.field("inputs", Lite(&_val.inputs));
+ }
+ if let Some(val) = &_val.variadic {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Variadic);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("variadic", Print::ref_cast(val));
+ }
+ formatter.field("output", Lite(&_val.output));
+ formatter.finish()
+ }
+ syn::Type::Group(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Group");
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+ syn::Type::ImplTrait(_val) => {
+ let mut formatter = formatter.debug_struct("Type::ImplTrait");
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+ syn::Type::Infer(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Infer");
+ formatter.finish()
+ }
+ syn::Type::Macro(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Macro");
+ formatter.field("mac", Lite(&_val.mac));
+ formatter.finish()
+ }
+ syn::Type::Never(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Never");
+ formatter.finish()
+ }
+ syn::Type::Paren(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Paren");
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+ syn::Type::Path(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Path");
+ if let Some(val) = &_val.qself {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::QSelf);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("qself", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+ syn::Type::Ptr(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Ptr");
+ if let Some(val) = &_val.const_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Const);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("const_token", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+ syn::Type::Reference(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Reference");
+ if let Some(val) = &_val.lifetime {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Lifetime);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("lifetime", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+ syn::Type::Slice(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Slice");
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+ syn::Type::TraitObject(_val) => {
+ let mut formatter = formatter.debug_struct("Type::TraitObject");
+ if let Some(val) = &_val.dyn_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Dyn);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("dyn_token", Print::ref_cast(val));
+ }
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+ syn::Type::Tuple(_val) => {
+ let mut formatter = formatter.debug_struct("Type::Tuple");
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+ syn::Type::Verbatim(_val) => {
+ formatter.write_str("Verbatim")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+impl Debug for Lite<syn::TypeArray> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeArray");
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.field("len", Lite(&_val.len));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeBareFn> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeBareFn");
+ if let Some(val) = &_val.lifetimes {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::BoundLifetimes);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("lifetimes", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.unsafety {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Unsafe);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("unsafety", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.abi {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Abi);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("abi", Print::ref_cast(val));
+ }
+ if !_val.inputs.is_empty() {
+ formatter.field("inputs", Lite(&_val.inputs));
+ }
+ if let Some(val) = &_val.variadic {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Variadic);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("variadic", Print::ref_cast(val));
+ }
+ formatter.field("output", Lite(&_val.output));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeGroup> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeGroup");
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeImplTrait> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeImplTrait");
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeInfer> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeInfer");
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeMacro> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeMacro");
+ formatter.field("mac", Lite(&_val.mac));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeNever> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeNever");
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeParam> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeParam");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ if let Some(val) = &_val.colon_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Colon);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("colon_token", Print::ref_cast(val));
+ }
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ if let Some(val) = &_val.eq_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Eq);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("eq_token", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.default {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Type);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("default", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeParamBound> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::TypeParamBound::Trait(_val) => {
+ formatter.write_str("Trait")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::TypeParamBound::Lifetime(_val) => {
+ formatter.write_str("Lifetime")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::TypeParen> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeParen");
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypePath> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypePath");
+ if let Some(val) = &_val.qself {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::QSelf);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("qself", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypePtr> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypePtr");
+ if let Some(val) = &_val.const_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Const);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("const_token", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeReference> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeReference");
+ if let Some(val) = &_val.lifetime {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::Lifetime);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("lifetime", Print::ref_cast(val));
+ }
+ if let Some(val) = &_val.mutability {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Mut);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("mutability", Print::ref_cast(val));
+ }
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeSlice> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeSlice");
+ formatter.field("elem", Lite(&_val.elem));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeTraitObject> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeTraitObject");
+ if let Some(val) = &_val.dyn_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::Dyn);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("dyn_token", Print::ref_cast(val));
+ }
+ if !_val.bounds.is_empty() {
+ formatter.field("bounds", Lite(&_val.bounds));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::TypeTuple> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("TypeTuple");
+ if !_val.elems.is_empty() {
+ formatter.field("elems", Lite(&_val.elems));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::UnOp> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::UnOp::Deref(_val) => {
+ formatter.write_str("Deref")?;
+ Ok(())
+ }
+ syn::UnOp::Not(_val) => {
+ formatter.write_str("Not")?;
+ Ok(())
+ }
+ syn::UnOp::Neg(_val) => {
+ formatter.write_str("Neg")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::UseGlob> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("UseGlob");
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::UseGroup> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("UseGroup");
+ if !_val.items.is_empty() {
+ formatter.field("items", Lite(&_val.items));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::UseName> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("UseName");
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::UsePath> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("UsePath");
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("tree", Lite(&_val.tree));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::UseRename> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("UseRename");
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("rename", Lite(&_val.rename));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::UseTree> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::UseTree::Path(_val) => {
+ formatter.write_str("Path")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::UseTree::Name(_val) => {
+ formatter.write_str("Name")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::UseTree::Rename(_val) => {
+ formatter.write_str("Rename")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::UseTree::Glob(_val) => {
+ formatter.write_str("Glob")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::UseTree::Group(_val) => {
+ formatter.write_str("Group")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
+impl Debug for Lite<syn::Variadic> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Variadic");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Variant> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("Variant");
+ if !_val.attrs.is_empty() {
+ formatter.field("attrs", Lite(&_val.attrs));
+ }
+ formatter.field("ident", Lite(&_val.ident));
+ formatter.field("fields", Lite(&_val.fields));
+ if let Some(val) = &_val.discriminant {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print((syn::token::Eq, syn::Expr));
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ let _val = &self.0;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(&_val.1), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ formatter.field("discriminant", Print::ref_cast(val));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::VisCrate> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("VisCrate");
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::VisPublic> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("VisPublic");
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::VisRestricted> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("VisRestricted");
+ if let Some(val) = &_val.in_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::In);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("in_token", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::Visibility> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::Visibility::Public(_val) => {
+ let mut formatter = formatter.debug_struct("Visibility::Public");
+ formatter.finish()
+ }
+ syn::Visibility::Crate(_val) => {
+ let mut formatter = formatter.debug_struct("Visibility::Crate");
+ formatter.finish()
+ }
+ syn::Visibility::Restricted(_val) => {
+ let mut formatter = formatter.debug_struct("Visibility::Restricted");
+ if let Some(val) = &_val.in_token {
+ #[derive(RefCast)]
+ #[repr(transparent)]
+ struct Print(syn::token::In);
+ impl Debug for Print {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("Some")?;
+ Ok(())
+ }
+ }
+ formatter.field("in_token", Print::ref_cast(val));
+ }
+ formatter.field("path", Lite(&_val.path));
+ formatter.finish()
+ }
+ syn::Visibility::Inherited => formatter.write_str("Inherited"),
+ }
+ }
+}
+impl Debug for Lite<syn::WhereClause> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ let mut formatter = formatter.debug_struct("WhereClause");
+ if !_val.predicates.is_empty() {
+ formatter.field("predicates", Lite(&_val.predicates));
+ }
+ formatter.finish()
+ }
+}
+impl Debug for Lite<syn::WherePredicate> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ let _val = &self.value;
+ match _val {
+ syn::WherePredicate::Type(_val) => {
+ formatter.write_str("Type")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::WherePredicate::Lifetime(_val) => {
+ formatter.write_str("Lifetime")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ syn::WherePredicate::Eq(_val) => {
+ formatter.write_str("Eq")?;
+ formatter.write_str("(")?;
+ Debug::fmt(Lite(_val), formatter)?;
+ formatter.write_str(")")?;
+ Ok(())
+ }
+ }
+ }
+}
diff --git a/syn/tests/debug/mod.rs b/syn/tests/debug/mod.rs
new file mode 100644
index 0000000..9c80e2c
--- /dev/null
+++ b/syn/tests/debug/mod.rs
@@ -0,0 +1,110 @@
+mod gen;
+
+use proc_macro2::{Ident, Literal, TokenStream};
+use ref_cast::RefCast;
+use std::fmt::{self, Debug};
+use std::ops::Deref;
+use syn::punctuated::Punctuated;
+
+#[derive(RefCast)]
+#[repr(transparent)]
+pub struct Lite<T: ?Sized> {
+ value: T,
+}
+
+#[allow(non_snake_case)]
+pub fn Lite<T: ?Sized>(value: &T) -> &Lite<T> {
+ Lite::ref_cast(value)
+}
+
+impl<T: ?Sized> Deref for Lite<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+}
+
+impl Debug for Lite<bool> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{}", self.value)
+ }
+}
+
+impl Debug for Lite<u32> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{}", self.value)
+ }
+}
+
+impl Debug for Lite<usize> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{}", self.value)
+ }
+}
+
+impl Debug for Lite<String> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{:?}", self.value)
+ }
+}
+
+impl Debug for Lite<Ident> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{:?}", self.value.to_string())
+ }
+}
+
+impl Debug for Lite<Literal> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{}", self.value)
+ }
+}
+
+impl Debug for Lite<TokenStream> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "`{}`", self.value)
+ }
+}
+
+impl<'a, T> Debug for Lite<&'a T>
+where
+ Lite<T>: Debug,
+{
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ Debug::fmt(Lite(&*self.value), formatter)
+ }
+}
+
+impl<T> Debug for Lite<Box<T>>
+where
+ Lite<T>: Debug,
+{
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ Debug::fmt(Lite(&*self.value), formatter)
+ }
+}
+
+impl<T> Debug for Lite<Vec<T>>
+where
+ Lite<T>: Debug,
+{
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_list()
+ .entries(self.value.iter().map(Lite))
+ .finish()
+ }
+}
+
+impl<T, P> Debug for Lite<Punctuated<T, P>>
+where
+ Lite<T>: Debug,
+{
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter
+ .debug_list()
+ .entries(self.value.iter().map(Lite))
+ .finish()
+ }
+}
diff --git a/syn/tests/features/error.rs b/syn/tests/features/error.rs
new file mode 100644
index 0000000..10ac889
--- /dev/null
+++ b/syn/tests/features/error.rs
@@ -0,0 +1 @@
+"Hello! You want: cargo test --release --all-features"
diff --git a/syn/tests/features/mod.rs b/syn/tests/features/mod.rs
new file mode 100644
index 0000000..83fbe13
--- /dev/null
+++ b/syn/tests/features/mod.rs
@@ -0,0 +1,22 @@
+#[allow(unused_macros)]
+macro_rules! hide_from_rustfmt {
+ ($mod:item) => {
+ $mod
+ };
+}
+
+#[cfg(not(all(
+ feature = "derive",
+ feature = "full",
+ feature = "parsing",
+ feature = "printing",
+ feature = "visit",
+ feature = "visit-mut",
+ feature = "fold",
+ feature = "clone-impls",
+ feature = "extra-traits",
+ feature = "proc-macro",
+)))]
+hide_from_rustfmt! {
+ mod error;
+}
diff --git a/syn/tests/macros/mod.rs b/syn/tests/macros/mod.rs
new file mode 100644
index 0000000..3994615
--- /dev/null
+++ b/syn/tests/macros/mod.rs
@@ -0,0 +1,76 @@
+#[path = "../debug/mod.rs"]
+pub mod debug;
+
+use syn;
+use syn::parse::{Parse, Result};
+
+#[macro_export]
+macro_rules! errorf {
+ ($($tt:tt)*) => {{
+ use ::std::io::Write;
+ let stderr = ::std::io::stderr();
+ write!(stderr.lock(), $($tt)*).unwrap();
+ }};
+}
+
+#[macro_export]
+macro_rules! punctuated {
+ ($($e:expr,)+) => {{
+ let mut seq = ::syn::punctuated::Punctuated::new();
+ $(
+ seq.push($e);
+ )+
+ seq
+ }};
+
+ ($($e:expr),+) => {
+ punctuated!($($e,)+)
+ };
+}
+
+#[macro_export]
+macro_rules! snapshot {
+ ($($args:tt)*) => {
+ snapshot_impl!(() $($args)*)
+ };
+}
+
+#[macro_export]
+macro_rules! snapshot_impl {
+ (($expr:ident) as $t:ty, @$snapshot:literal) => {
+ let $expr = crate::macros::Tokens::parse::<$t>($expr).unwrap();
+ let debug = crate::macros::debug::Lite(&$expr);
+ insta::assert_debug_snapshot!(debug, @$snapshot);
+ };
+ (($($expr:tt)*) as $t:ty, @$snapshot:literal) => {{
+ let syntax_tree = crate::macros::Tokens::parse::<$t>($($expr)*).unwrap();
+ let debug = crate::macros::debug::Lite(&syntax_tree);
+ insta::assert_debug_snapshot!(debug, @$snapshot);
+ syntax_tree
+ }};
+ (($($expr:tt)*) , @$snapshot:literal) => {{
+ let syntax_tree = $($expr)*;
+ let debug = crate::macros::debug::Lite(&syntax_tree);
+ insta::assert_debug_snapshot!(debug, @$snapshot);
+ syntax_tree
+ }};
+ (($($expr:tt)*) $next:tt $($rest:tt)*) => {
+ snapshot_impl!(($($expr)* $next) $($rest)*)
+ };
+}
+
+pub trait Tokens {
+ fn parse<T: Parse>(self) -> Result<T>;
+}
+
+impl<'a> Tokens for &'a str {
+ fn parse<T: Parse>(self) -> Result<T> {
+ syn::parse_str(self)
+ }
+}
+
+impl Tokens for proc_macro2::TokenStream {
+ fn parse<T: Parse>(self) -> Result<T> {
+ syn::parse2(self)
+ }
+}
diff --git a/syn/tests/repo/mod.rs b/syn/tests/repo/mod.rs
new file mode 100644
index 0000000..681615c
--- /dev/null
+++ b/syn/tests/repo/mod.rs
@@ -0,0 +1,109 @@
+mod progress;
+
+use self::progress::Progress;
+use crate::common;
+use anyhow::Result;
+use flate2::read::GzDecoder;
+use std::fs;
+use std::path::Path;
+use tar::Archive;
+use walkdir::DirEntry;
+
+const REVISION: &str = "7979016aff545f7b41cc517031026020b340989d";
+
+pub fn base_dir_filter(entry: &DirEntry) -> bool {
+ let path = entry.path();
+ if path.is_dir() {
+ return true; // otherwise walkdir does not visit the files
+ }
+ if path.extension().map(|e| e != "rs").unwrap_or(true) {
+ return false;
+ }
+ let path_string = path.to_string_lossy();
+ let path_string = if cfg!(windows) {
+ path_string.replace('\\', "/").into()
+ } else {
+ path_string
+ };
+ // TODO assert that parsing fails on the parse-fail cases
+ if path_string.starts_with("tests/rust/src/test/parse-fail")
+ || path_string.starts_with("tests/rust/src/test/compile-fail")
+ || path_string.starts_with("tests/rust/src/test/rustfix")
+ {
+ return false;
+ }
+
+ if path_string.starts_with("tests/rust/src/test/ui") {
+ let stderr_path = path.with_extension("stderr");
+ if stderr_path.exists() {
+ // Expected to fail in some way
+ return false;
+ }
+ }
+
+ match path_string.as_ref() {
+ // Deprecated placement syntax
+ "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
+ // Deprecated anonymous parameter syntax in traits
+ "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
+ "tests/rust/src/test/ui/issues/issue-13105.rs" |
+ "tests/rust/src/test/ui/issues/issue-13775.rs" |
+ "tests/rust/src/test/ui/issues/issue-34074.rs" |
+ // Deprecated await macro syntax
+ "tests/rust/src/test/ui/async-await/await-macro.rs" |
+ // 2015-style dyn that libsyntax rejects
+ "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
+ // not actually test cases
+ "tests/rust/src/test/ui/include-single-expr-helper.rs" |
+ "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
+ "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
+ "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
+ "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
+ _ => true,
+ }
+}
+
+pub fn clone_rust() {
+ let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
+ Err(_) => true,
+ Ok(contents) => contents.trim() != REVISION,
+ };
+ if needs_clone {
+ download_and_unpack().unwrap();
+ }
+}
+
+fn download_and_unpack() -> Result<()> {
+ let url = format!(
+ "https://github.com/rust-lang/rust/archive/{}.tar.gz",
+ REVISION
+ );
+ let response = reqwest::blocking::get(&url)?.error_for_status()?;
+ let progress = Progress::new(response);
+ let decoder = GzDecoder::new(progress);
+ let mut archive = Archive::new(decoder);
+ let prefix = format!("rust-{}", REVISION);
+
+ let tests_rust = Path::new("tests/rust");
+ if tests_rust.exists() {
+ fs::remove_dir_all(tests_rust)?;
+ }
+
+ for entry in archive.entries()? {
+ let mut entry = entry?;
+ let path = entry.path()?;
+ if path == Path::new("pax_global_header") {
+ continue;
+ }
+ let relative = path.strip_prefix(&prefix)?;
+ let out = tests_rust.join(relative);
+ entry.unpack(&out)?;
+ if common::travis_ci() {
+ // Something about this makes the travis build not deadlock...
+ errorf!(".");
+ }
+ }
+
+ fs::write("tests/rust/COMMIT", REVISION)?;
+ Ok(())
+}
diff --git a/syn/tests/repo/progress.rs b/syn/tests/repo/progress.rs
new file mode 100644
index 0000000..28c8a44
--- /dev/null
+++ b/syn/tests/repo/progress.rs
@@ -0,0 +1,37 @@
+use std::io::{Read, Result};
+use std::time::{Duration, Instant};
+
+pub struct Progress<R> {
+ bytes: usize,
+ tick: Instant,
+ stream: R,
+}
+
+impl<R> Progress<R> {
+ pub fn new(stream: R) -> Self {
+ Progress {
+ bytes: 0,
+ tick: Instant::now() + Duration::from_millis(2000),
+ stream,
+ }
+ }
+}
+
+impl<R: Read> Read for Progress<R> {
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+ let num = self.stream.read(buf)?;
+ self.bytes += num;
+ let now = Instant::now();
+ if now > self.tick {
+ self.tick = now + Duration::from_millis(500);
+ errorf!("downloading... {} bytes\n", self.bytes);
+ }
+ Ok(num)
+ }
+}
+
+impl<R> Drop for Progress<R> {
+ fn drop(&mut self) {
+ errorf!("done ({} bytes)\n", self.bytes);
+ }
+}
diff --git a/syn/tests/test_asyncness.rs b/syn/tests/test_asyncness.rs
new file mode 100644
index 0000000..e09e816
--- /dev/null
+++ b/syn/tests/test_asyncness.rs
@@ -0,0 +1,39 @@
+mod features;
+
+#[macro_use]
+mod macros;
+
+use syn::{Expr, Item};
+
+#[test]
+fn test_async_fn() {
+ let input = "async fn process() {}";
+
+ snapshot!(input as Item, @r###"
+ Item::Fn {
+ vis: Inherited,
+ sig: Signature {
+ asyncness: Some,
+ ident: "process",
+ generics: Generics,
+ output: Default,
+ },
+ block: Block,
+ }
+ "###);
+}
+
+#[test]
+fn test_async_closure() {
+ let input = "async || {}";
+
+ snapshot!(input as Expr, @r###"
+ Expr::Closure {
+ asyncness: Some,
+ output: Default,
+ body: Expr::Block {
+ block: Block,
+ },
+ }
+ "###);
+}
diff --git a/syn/tests/test_attribute.rs b/syn/tests/test_attribute.rs
new file mode 100644
index 0000000..d77c0c0
--- /dev/null
+++ b/syn/tests/test_attribute.rs
@@ -0,0 +1,296 @@
+mod features;
+
+#[macro_use]
+mod macros;
+
+use syn::parse::Parser;
+use syn::{Attribute, Meta};
+
+#[test]
+fn test_meta_item_word() {
+ let meta = test("#[foo]");
+
+ snapshot!(meta, @r###"
+ Path(Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ })
+ "###);
+}
+
+#[test]
+fn test_meta_item_name_value() {
+ let meta = test("#[foo = 5]");
+
+ snapshot!(meta, @r###"
+ Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }
+ "###);
+}
+
+#[test]
+fn test_meta_item_bool_value() {
+ let meta = test("#[foo = true]");
+
+ snapshot!(meta, @r###"
+ Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ lit: Lit::Bool {
+ value: true,
+ },
+ }
+ "###);
+
+ let meta = test("#[foo = false]");
+
+ snapshot!(meta, @r###"
+ Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ lit: Lit::Bool {
+ value: false,
+ },
+ }
+ "###);
+}
+
+#[test]
+fn test_meta_item_list_lit() {
+ let meta = test("#[foo(5)]");
+
+ snapshot!(meta, @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Lit(5),
+ ],
+ }
+ "###);
+}
+
+#[test]
+fn test_meta_item_list_word() {
+ let meta = test("#[foo(bar)]");
+
+ snapshot!(meta, @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "bar",
+ arguments: None,
+ },
+ ],
+ })),
+ ],
+ }
+ "###);
+}
+
+#[test]
+fn test_meta_item_list_name_value() {
+ let meta = test("#[foo(bar = 5)]");
+
+ snapshot!(meta, @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "bar",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }),
+ ],
+ }
+ "###);
+}
+
+#[test]
+fn test_meta_item_list_bool_value() {
+ let meta = test("#[foo(bar = true)]");
+
+ snapshot!(meta, @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "bar",
+ arguments: None,
+ },
+ ],
+ },
+ lit: Lit::Bool {
+ value: true,
+ },
+ }),
+ ],
+ }
+ "###);
+}
+
+#[test]
+fn test_meta_item_multiple() {
+ let meta = test("#[foo(word, name = 5, list(name2 = 6), word2)]");
+
+ snapshot!(meta, @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "word",
+ arguments: None,
+ },
+ ],
+ })),
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "name",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }),
+ Meta(Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "list",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "name2",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 6,
+ }),
+ ],
+ }),
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "word2",
+ arguments: None,
+ },
+ ],
+ })),
+ ],
+ }
+ "###);
+}
+
+#[test]
+fn test_bool_lit() {
+ let meta = test("#[foo(true)]");
+
+ snapshot!(meta, @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Lit(Lit::Bool {
+ value: true,
+ }),
+ ],
+ }
+ "###);
+}
+
+fn test(input: &str) -> Meta {
+ let attrs = Attribute::parse_outer.parse_str(input).unwrap();
+
+ assert_eq!(attrs.len(), 1);
+ let attr = attrs.into_iter().next().unwrap();
+
+ attr.parse_meta().unwrap()
+}
diff --git a/syn/tests/test_derive_input.rs b/syn/tests/test_derive_input.rs
new file mode 100644
index 0000000..e3685ae
--- /dev/null
+++ b/syn/tests/test_derive_input.rs
@@ -0,0 +1,894 @@
+mod features;
+
+#[macro_use]
+mod macros;
+
+use quote::quote;
+use syn::{Data, DeriveInput};
+
+#[test]
+fn test_unit() {
+ let input = quote! {
+ struct Unit;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Inherited,
+ ident: "Unit",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+}
+
+#[test]
+fn test_struct() {
+ let input = quote! {
+ #[derive(Debug, Clone)]
+ pub struct Item {
+ pub ident: Ident,
+ pub attrs: Vec<Attribute>
+ }
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ attrs: [
+ Attribute {
+ style: Outer,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "derive",
+ arguments: None,
+ },
+ ],
+ },
+ tokens: `( Debug , Clone )`,
+ },
+ ],
+ vis: Visibility::Public,
+ ident: "Item",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Fields::Named {
+ named: [
+ Field {
+ vis: Visibility::Public,
+ ident: Some("ident"),
+ colon_token: Some,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "Ident",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ Field {
+ vis: Visibility::Public,
+ ident: Some("attrs"),
+ colon_token: Some,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "Vec",
+ arguments: PathArguments::AngleBracketed {
+ args: [
+ Type(Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "Attribute",
+ arguments: None,
+ },
+ ],
+ },
+ }),
+ ],
+ },
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ },
+ }
+ "###);
+
+ snapshot!(input.attrs[0].parse_meta().unwrap(), @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "derive",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "Debug",
+ arguments: None,
+ },
+ ],
+ })),
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "Clone",
+ arguments: None,
+ },
+ ],
+ })),
+ ],
+ }
+ "###);
+}
+
+#[test]
+fn test_union() {
+ let input = quote! {
+ union MaybeUninit<T> {
+ uninit: (),
+ value: T
+ }
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Inherited,
+ ident: "MaybeUninit",
+ generics: Generics {
+ lt_token: Some,
+ params: [
+ Type(TypeParam {
+ ident: "T",
+ }),
+ ],
+ gt_token: Some,
+ },
+ data: Data::Union {
+ fields: FieldsNamed {
+ named: [
+ Field {
+ vis: Inherited,
+ ident: Some("uninit"),
+ colon_token: Some,
+ ty: Type::Tuple,
+ },
+ Field {
+ vis: Inherited,
+ ident: Some("value"),
+ colon_token: Some,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "T",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ },
+ }
+ "###);
+}
+
+#[test]
+#[cfg(feature = "full")]
+fn test_enum() {
+ let input = quote! {
+ /// See the std::result module documentation for details.
+ #[must_use]
+ pub enum Result<T, E> {
+ Ok(T),
+ Err(E),
+ Surprise = 0isize,
+
+ // Smuggling data into a proc_macro_derive,
+ // in the style of https://github.com/dtolnay/proc-macro-hack
+ ProcMacroHack = (0, "data").0
+ }
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ attrs: [
+ Attribute {
+ style: Outer,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "doc",
+ arguments: None,
+ },
+ ],
+ },
+ tokens: `= r" See the std::result module documentation for details."`,
+ },
+ Attribute {
+ style: Outer,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "must_use",
+ arguments: None,
+ },
+ ],
+ },
+ tokens: ``,
+ },
+ ],
+ vis: Visibility::Public,
+ ident: "Result",
+ generics: Generics {
+ lt_token: Some,
+ params: [
+ Type(TypeParam {
+ ident: "T",
+ }),
+ Type(TypeParam {
+ ident: "E",
+ }),
+ ],
+ gt_token: Some,
+ },
+ data: Data::Enum {
+ variants: [
+ Variant {
+ ident: "Ok",
+ fields: Fields::Unnamed {
+ unnamed: [
+ Field {
+ vis: Inherited,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "T",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ },
+ Variant {
+ ident: "Err",
+ fields: Fields::Unnamed {
+ unnamed: [
+ Field {
+ vis: Inherited,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "E",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ },
+ Variant {
+ ident: "Surprise",
+ fields: Unit,
+ discriminant: Some(Expr::Lit {
+ lit: 0isize,
+ }),
+ },
+ Variant {
+ ident: "ProcMacroHack",
+ fields: Unit,
+ discriminant: Some(Expr::Field {
+ base: Expr::Tuple {
+ elems: [
+ Expr::Lit {
+ lit: 0,
+ },
+ Expr::Lit {
+ lit: "data",
+ },
+ ],
+ },
+ member: Unnamed(Index {
+ index: 0,
+ }),
+ }),
+ },
+ ],
+ },
+ }
+ "###);
+
+ let meta_items: Vec<_> = input
+ .attrs
+ .into_iter()
+ .map(|attr| attr.parse_meta().unwrap())
+ .collect();
+
+ snapshot!(meta_items, @r###"
+ [
+ Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "doc",
+ arguments: None,
+ },
+ ],
+ },
+ lit: " See the std::result module documentation for details.",
+ },
+ Path(Path {
+ segments: [
+ PathSegment {
+ ident: "must_use",
+ arguments: None,
+ },
+ ],
+ }),
+ ]
+ "###);
+}
+
+#[test]
+fn test_attr_with_path() {
+ let input = quote! {
+ #[::attr_args::identity
+ fn main() { assert_eq!(foo(), "Hello, world!"); }]
+ struct Dummy;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ attrs: [
+ Attribute {
+ style: Outer,
+ path: Path {
+ leading_colon: Some,
+ segments: [
+ PathSegment {
+ ident: "attr_args",
+ arguments: None,
+ },
+ PathSegment {
+ ident: "identity",
+ arguments: None,
+ },
+ ],
+ },
+ tokens: `fn main ( ) { assert_eq ! ( foo ( ) , "Hello, world!" ) ; }`,
+ },
+ ],
+ vis: Inherited,
+ ident: "Dummy",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+
+ assert!(input.attrs[0].parse_meta().is_err());
+}
+
+#[test]
+fn test_attr_with_non_mod_style_path() {
+ let input = quote! {
+ #[inert <T>]
+ struct S;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ attrs: [
+ Attribute {
+ style: Outer,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "inert",
+ arguments: None,
+ },
+ ],
+ },
+ tokens: `< T >`,
+ },
+ ],
+ vis: Inherited,
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+
+ assert!(input.attrs[0].parse_meta().is_err());
+}
+
+#[test]
+fn test_attr_with_mod_style_path_with_self() {
+ let input = quote! {
+ #[foo::self]
+ struct S;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ attrs: [
+ Attribute {
+ style: Outer,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ PathSegment {
+ ident: "self",
+ arguments: None,
+ },
+ ],
+ },
+ tokens: ``,
+ },
+ ],
+ vis: Inherited,
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+
+ snapshot!(input.attrs[0].parse_meta().unwrap(), @r###"
+ Path(Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ PathSegment {
+ ident: "self",
+ arguments: None,
+ },
+ ],
+ })
+ "###);
+}
+
+#[test]
+fn test_pub_restricted() {
+ // Taken from tests/rust/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs
+ let input = quote! {
+ pub(in m) struct Z(pub(in m::n) u8);
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Visibility::Restricted {
+ in_token: Some,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "m",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ ident: "Z",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Fields::Unnamed {
+ unnamed: [
+ Field {
+ vis: Visibility::Restricted {
+ in_token: Some,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "m",
+ arguments: None,
+ },
+ PathSegment {
+ ident: "n",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "u8",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ semi_token: Some,
+ },
+ }
+ "###);
+}
+
+#[test]
+fn test_vis_crate() {
+ let input = quote! {
+ crate struct S;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Visibility::Crate,
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+}
+
+#[test]
+fn test_pub_restricted_crate() {
+ let input = quote! {
+ pub(crate) struct S;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Visibility::Restricted {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "crate",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+}
+
+#[test]
+fn test_pub_restricted_super() {
+ let input = quote! {
+ pub(super) struct S;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Visibility::Restricted {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "super",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+}
+
+#[test]
+fn test_pub_restricted_in_super() {
+ let input = quote! {
+ pub(in super) struct S;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Visibility::Restricted {
+ in_token: Some,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "super",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+}
+
+#[test]
+fn test_fields_on_unit_struct() {
+ let input = quote! {
+ struct S;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Inherited,
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+
+ let data = match input.data {
+ Data::Struct(data) => data,
+ _ => panic!("expected a struct"),
+ };
+
+ assert_eq!(0, data.fields.iter().count());
+}
+
+#[test]
+fn test_fields_on_named_struct() {
+ let input = quote! {
+ struct S {
+ foo: i32,
+ pub bar: String,
+ }
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Inherited,
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Fields::Named {
+ named: [
+ Field {
+ vis: Inherited,
+ ident: Some("foo"),
+ colon_token: Some,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "i32",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ Field {
+ vis: Visibility::Public,
+ ident: Some("bar"),
+ colon_token: Some,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "String",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ },
+ }
+ "###);
+
+ let data = match input.data {
+ Data::Struct(data) => data,
+ _ => panic!("expected a struct"),
+ };
+
+ snapshot!(data.fields.into_iter().collect::<Vec<_>>(), @r###"
+ [
+ Field {
+ vis: Inherited,
+ ident: Some("foo"),
+ colon_token: Some,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "i32",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ Field {
+ vis: Visibility::Public,
+ ident: Some("bar"),
+ colon_token: Some,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "String",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ]
+ "###);
+}
+
+#[test]
+fn test_fields_on_tuple_struct() {
+ let input = quote! {
+ struct S(i32, pub String);
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Inherited,
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Fields::Unnamed {
+ unnamed: [
+ Field {
+ vis: Inherited,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "i32",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ Field {
+ vis: Visibility::Public,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "String",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ semi_token: Some,
+ },
+ }
+ "###);
+
+ let data = match input.data {
+ Data::Struct(data) => data,
+ _ => panic!("expected a struct"),
+ };
+
+ snapshot!(data.fields.iter().collect::<Vec<_>>(), @r###"
+ [
+ Field {
+ vis: Inherited,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "i32",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ Field {
+ vis: Visibility::Public,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "String",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ]
+ "###);
+}
+
+#[test]
+fn test_ambiguous_crate() {
+ let input = quote! {
+ // The field type is `(crate::X)` not `crate (::X)`.
+ struct S(crate::X);
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Inherited,
+ ident: "S",
+ generics: Generics,
+ data: Data::Struct {
+ fields: Fields::Unnamed {
+ unnamed: [
+ Field {
+ vis: Inherited,
+ ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "crate",
+ arguments: None,
+ },
+ PathSegment {
+ ident: "X",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ semi_token: Some,
+ },
+ }
+ "###);
+}
diff --git a/syn/tests/test_expr.rs b/syn/tests/test_expr.rs
new file mode 100644
index 0000000..0edf6ce
--- /dev/null
+++ b/syn/tests/test_expr.rs
@@ -0,0 +1,37 @@
+#[macro_use]
+mod macros;
+
+use std::str::FromStr;
+
+use proc_macro2::TokenStream;
+use syn::{Expr, ExprRange};
+
+#[test]
+fn test_expr_parse() {
+ let code = "..100u32";
+ let tt = TokenStream::from_str(code).unwrap();
+ let expr: Expr = syn::parse2(tt.clone()).unwrap();
+ let expr_range: ExprRange = syn::parse2(tt).unwrap();
+ assert_eq!(expr, Expr::Range(expr_range));
+}
+
+#[test]
+fn test_await() {
+ // Must not parse as Expr::Field.
+ let expr = syn::parse_str::<Expr>("fut.await").unwrap();
+
+ snapshot!(expr, @r###"
+ Expr::Await {
+ base: Expr::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "fut",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ }
+ "###);
+}
diff --git a/syn/tests/test_generics.rs b/syn/tests/test_generics.rs
new file mode 100644
index 0000000..e863b77
--- /dev/null
+++ b/syn/tests/test_generics.rs
@@ -0,0 +1,285 @@
+mod features;
+
+#[macro_use]
+mod macros;
+
+use quote::quote;
+use syn::{DeriveInput, ItemFn, TypeParamBound, WhereClause, WherePredicate};
+
+#[test]
+fn test_split_for_impl() {
+ let input = quote! {
+ struct S<'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug;
+ };
+
+ snapshot!(input as DeriveInput, @r###"
+ DeriveInput {
+ vis: Inherited,
+ ident: "S",
+ generics: Generics {
+ lt_token: Some,
+ params: [
+ Lifetime(LifetimeDef {
+ lifetime: Lifetime {
+ ident: "a",
+ },
+ }),
+ Lifetime(LifetimeDef {
+ lifetime: Lifetime {
+ ident: "b",
+ },
+ colon_token: Some,
+ bounds: [
+ Lifetime {
+ ident: "a",
+ },
+ ],
+ }),
+ Type(TypeParam {
+ attrs: [
+ Attribute {
+ style: Outer,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "may_dangle",
+ arguments: None,
+ },
+ ],
+ },
+ tokens: ``,
+ },
+ ],
+ ident: "T",
+ colon_token: Some,
+ bounds: [
+ Lifetime(Lifetime {
+ ident: "a",
+ }),
+ ],
+ eq_token: Some,
+ default: Some(Type::Tuple),
+ }),
+ ],
+ gt_token: Some,
+ where_clause: Some(WhereClause {
+ predicates: [
+ Type(PredicateType {
+ bounded_ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "T",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ bounds: [
+ Trait(TraitBound {
+ modifier: None,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "Debug",
+ arguments: None,
+ },
+ ],
+ },
+ }),
+ ],
+ }),
+ ],
+ }),
+ },
+ data: Data::Struct {
+ fields: Unit,
+ semi_token: Some,
+ },
+ }
+ "###);
+
+ let generics = input.generics;
+ let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+
+ let generated = quote! {
+ impl #impl_generics MyTrait for Test #ty_generics #where_clause {}
+ };
+ let expected = quote! {
+ impl<'a, 'b: 'a, #[may_dangle] T: 'a> MyTrait
+ for Test<'a, 'b, T>
+ where
+ T: Debug
+ {}
+ };
+ assert_eq!(generated.to_string(), expected.to_string());
+
+ let turbofish = ty_generics.as_turbofish();
+ let generated = quote! {
+ Test #turbofish
+ };
+ let expected = quote! {
+ Test::<'a, 'b, T>
+ };
+ assert_eq!(generated.to_string(), expected.to_string());
+}
+
+#[test]
+fn test_ty_param_bound() {
+ let tokens = quote!('a);
+ snapshot!(tokens as TypeParamBound, @r###"
+ Lifetime(Lifetime {
+ ident: "a",
+ })
+ "###);
+
+ let tokens = quote!('_);
+ snapshot!(tokens as TypeParamBound, @r###"
+ Lifetime(Lifetime {
+ ident: "_",
+ })
+ "###);
+
+ let tokens = quote!(Debug);
+ snapshot!(tokens as TypeParamBound, @r###"
+ Trait(TraitBound {
+ modifier: None,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "Debug",
+ arguments: None,
+ },
+ ],
+ },
+ })
+ "###);
+
+ let tokens = quote!(?Sized);
+ snapshot!(tokens as TypeParamBound, @r###"
+ Trait(TraitBound {
+ modifier: Maybe,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "Sized",
+ arguments: None,
+ },
+ ],
+ },
+ })
+ "###);
+}
+
+#[test]
+fn test_fn_precedence_in_where_clause() {
+ // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not
+ // `FnOnce() -> (i32 + Send)`.
+ let input = quote! {
+ fn f<G>()
+ where
+ G: FnOnce() -> i32 + Send,
+ {
+ }
+ };
+
+ snapshot!(input as ItemFn, @r###"
+ ItemFn {
+ vis: Inherited,
+ sig: Signature {
+ ident: "f",
+ generics: Generics {
+ lt_token: Some,
+ params: [
+ Type(TypeParam {
+ ident: "G",
+ }),
+ ],
+ gt_token: Some,
+ where_clause: Some(WhereClause {
+ predicates: [
+ Type(PredicateType {
+ bounded_ty: Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "G",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ bounds: [
+ Trait(TraitBound {
+ modifier: None,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "FnOnce",
+ arguments: PathArguments::Parenthesized {
+ output: Type(
+ Type::Path {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "i32",
+ arguments: None,
+ },
+ ],
+ },
+ },
+ ),
+ },
+ },
+ ],
+ },
+ }),
+ Trait(TraitBound {
+ modifier: None,
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "Send",
+ arguments: None,
+ },
+ ],
+ },
+ }),
+ ],
+ }),
+ ],
+ }),
+ },
+ output: Default,
+ },
+ block: Block,
+ }
+ "###);
+
+ let where_clause = input.sig.generics.where_clause.as_ref().unwrap();
+ assert_eq!(where_clause.predicates.len(), 1);
+
+ let predicate = match &where_clause.predicates[0] {
+ WherePredicate::Type(pred) => pred,
+ _ => panic!("wrong predicate kind"),
+ };
+
+ assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds);
+
+ let first_bound = &predicate.bounds[0];
+ assert_eq!(quote!(#first_bound).to_string(), "FnOnce ( ) -> i32");
+
+ let second_bound = &predicate.bounds[1];
+ assert_eq!(quote!(#second_bound).to_string(), "Send");
+}
+
+#[test]
+fn test_where_clause_at_end_of_input() {
+ let input = quote! {
+ where
+ };
+
+ snapshot!(input as WhereClause, @"WhereClause");
+
+ assert_eq!(input.predicates.len(), 0);
+}
diff --git a/syn/tests/test_grouping.rs b/syn/tests/test_grouping.rs
new file mode 100644
index 0000000..4e43ab8
--- /dev/null
+++ b/syn/tests/test_grouping.rs
@@ -0,0 +1,55 @@
+mod features;
+
+#[macro_use]
+mod macros;
+
+use proc_macro2::{Delimiter, Group, Literal, Punct, Spacing, TokenStream, TokenTree};
+use syn::Expr;
+
+use std::iter::FromIterator;
+
+#[test]
+fn test_grouping() {
+ let tokens: TokenStream = TokenStream::from_iter(vec![
+ TokenTree::Literal(Literal::i32_suffixed(1)),
+ TokenTree::Punct(Punct::new('+', Spacing::Alone)),
+ TokenTree::Group(Group::new(
+ Delimiter::None,
+ TokenStream::from_iter(vec![
+ TokenTree::Literal(Literal::i32_suffixed(2)),
+ TokenTree::Punct(Punct::new('+', Spacing::Alone)),
+ TokenTree::Literal(Literal::i32_suffixed(3)),
+ ]),
+ )),
+ TokenTree::Punct(Punct::new('*', Spacing::Alone)),
+ TokenTree::Literal(Literal::i32_suffixed(4)),
+ ]);
+
+ assert_eq!(tokens.to_string(), "1i32 + 2i32 + 3i32 * 4i32");
+
+ snapshot!(tokens as Expr, @r###"
+ Expr::Binary {
+ left: Expr::Lit {
+ lit: 1i32,
+ },
+ op: Add,
+ right: Expr::Binary {
+ left: Expr::Group {
+ expr: Expr::Binary {
+ left: Expr::Lit {
+ lit: 2i32,
+ },
+ op: Add,
+ right: Expr::Lit {
+ lit: 3i32,
+ },
+ },
+ },
+ op: Mul,
+ right: Expr::Lit {
+ lit: 4i32,
+ },
+ },
+ }
+ "###);
+}
diff --git a/syn/tests/test_ident.rs b/syn/tests/test_ident.rs
new file mode 100644
index 0000000..7578381
--- /dev/null
+++ b/syn/tests/test_ident.rs
@@ -0,0 +1,87 @@
+mod features;
+
+use proc_macro2::{Ident, Span, TokenStream};
+use std::str::FromStr;
+use syn::Result;
+
+fn parse(s: &str) -> Result<Ident> {
+ syn::parse2(TokenStream::from_str(s).unwrap())
+}
+
+fn new(s: &str) -> Ident {
+ Ident::new(s, Span::call_site())
+}
+
+#[test]
+fn ident_parse() {
+ parse("String").unwrap();
+}
+
+#[test]
+fn ident_parse_keyword() {
+ parse("abstract").unwrap_err();
+}
+
+#[test]
+fn ident_parse_empty() {
+ parse("").unwrap_err();
+}
+
+#[test]
+fn ident_parse_lifetime() {
+ parse("'static").unwrap_err();
+}
+
+#[test]
+fn ident_parse_underscore() {
+ parse("_").unwrap_err();
+}
+
+#[test]
+fn ident_parse_number() {
+ parse("255").unwrap_err();
+}
+
+#[test]
+fn ident_parse_invalid() {
+ parse("a#").unwrap_err();
+}
+
+#[test]
+fn ident_new() {
+ new("String");
+}
+
+#[test]
+fn ident_new_keyword() {
+ new("abstract");
+}
+
+#[test]
+#[should_panic(expected = "use Option<Ident>")]
+fn ident_new_empty() {
+ new("");
+}
+
+#[test]
+#[should_panic(expected = "not a valid Ident")]
+fn ident_new_lifetime() {
+ new("'static");
+}
+
+#[test]
+fn ident_new_underscore() {
+ new("_");
+}
+
+#[test]
+#[should_panic(expected = "use Literal instead")]
+fn ident_new_number() {
+ new("255");
+}
+
+#[test]
+#[should_panic(expected = "\"a#\" is not a valid Ident")]
+fn ident_new_invalid() {
+ new("a#");
+}
diff --git a/syn/tests/test_iterators.rs b/syn/tests/test_iterators.rs
new file mode 100644
index 0000000..f107297
--- /dev/null
+++ b/syn/tests/test_iterators.rs
@@ -0,0 +1,51 @@
+use syn::punctuated::{Pair, Punctuated};
+use syn::Token;
+
+mod features;
+
+#[macro_use]
+mod macros;
+
+macro_rules! check_exact_size_iterator {
+ ($iter:expr) => {{
+ let iter = $iter;
+ let size_hint = iter.size_hint();
+ let len = iter.len();
+ let count = iter.count();
+ assert_eq!(len, count);
+ assert_eq!(size_hint, (count, Some(count)));
+ }};
+}
+
+#[test]
+fn pairs() {
+ let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4);
+
+ check_exact_size_iterator!(p.pairs());
+ check_exact_size_iterator!(p.pairs_mut());
+ check_exact_size_iterator!(p.into_pairs());
+
+ let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4);
+
+ assert_eq!(p.pairs().next_back().map(Pair::into_value), Some(&4));
+ assert_eq!(
+ p.pairs_mut().next_back().map(Pair::into_value),
+ Some(&mut 4)
+ );
+ assert_eq!(p.into_pairs().next_back().map(Pair::into_value), Some(4));
+}
+
+#[test]
+fn iter() {
+ let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4);
+
+ check_exact_size_iterator!(p.iter());
+ check_exact_size_iterator!(p.iter_mut());
+ check_exact_size_iterator!(p.into_iter());
+
+ let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4);
+
+ assert_eq!(p.iter().next_back(), Some(&4));
+ assert_eq!(p.iter_mut().next_back(), Some(&mut 4));
+ assert_eq!(p.into_iter().next_back(), Some(4));
+}
diff --git a/syn/tests/test_lit.rs b/syn/tests/test_lit.rs
new file mode 100644
index 0000000..0b300c4
--- /dev/null
+++ b/syn/tests/test_lit.rs
@@ -0,0 +1,184 @@
+mod features;
+
+use proc_macro2::{TokenStream, TokenTree};
+use quote::ToTokens;
+use std::str::FromStr;
+use syn::Lit;
+
+fn lit(s: &str) -> Lit {
+ match TokenStream::from_str(s)
+ .unwrap()
+ .into_iter()
+ .next()
+ .unwrap()
+ {
+ TokenTree::Literal(lit) => Lit::new(lit),
+ _ => panic!(),
+ }
+}
+
+#[test]
+fn strings() {
+ fn test_string(s: &str, value: &str) {
+ match lit(s) {
+ Lit::Str(lit) => {
+ assert_eq!(lit.value(), value);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_string(&again, value);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_string("\"a\"", "a");
+ test_string("\"\\n\"", "\n");
+ test_string("\"\\r\"", "\r");
+ test_string("\"\\t\"", "\t");
+ test_string("\"🐕\"", "🐕"); // NOTE: This is an emoji
+ test_string("\"\\\"\"", "\"");
+ test_string("\"'\"", "'");
+ test_string("\"\"", "");
+ test_string("\"\\u{1F415}\"", "\u{1F415}");
+ test_string(
+ "\"contains\nnewlines\\\nescaped newlines\"",
+ "contains\nnewlinesescaped newlines",
+ );
+ test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere");
+}
+
+#[test]
+fn byte_strings() {
+ fn test_byte_string(s: &str, value: &[u8]) {
+ match lit(s) {
+ Lit::ByteStr(lit) => {
+ assert_eq!(lit.value(), value);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_byte_string(&again, value);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_byte_string("b\"a\"", b"a");
+ test_byte_string("b\"\\n\"", b"\n");
+ test_byte_string("b\"\\r\"", b"\r");
+ test_byte_string("b\"\\t\"", b"\t");
+ test_byte_string("b\"\\\"\"", b"\"");
+ test_byte_string("b\"'\"", b"'");
+ test_byte_string("b\"\"", b"");
+ test_byte_string(
+ "b\"contains\nnewlines\\\nescaped newlines\"",
+ b"contains\nnewlinesescaped newlines",
+ );
+ test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere");
+}
+
+#[test]
+fn bytes() {
+ fn test_byte(s: &str, value: u8) {
+ match lit(s) {
+ Lit::Byte(lit) => {
+ assert_eq!(lit.value(), value);
+ let again = lit.into_token_stream().to_string();
+ assert_eq!(again, s);
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_byte("b'a'", b'a');
+ test_byte("b'\\n'", b'\n');
+ test_byte("b'\\r'", b'\r');
+ test_byte("b'\\t'", b'\t');
+ test_byte("b'\\''", b'\'');
+ test_byte("b'\"'", b'"');
+}
+
+#[test]
+fn chars() {
+ fn test_char(s: &str, value: char) {
+ match lit(s) {
+ Lit::Char(lit) => {
+ assert_eq!(lit.value(), value);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_char(&again, value);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_char("'a'", 'a');
+ test_char("'\\n'", '\n');
+ test_char("'\\r'", '\r');
+ test_char("'\\t'", '\t');
+ test_char("'🐕'", '🐕'); // NOTE: This is an emoji
+ test_char("'\\''", '\'');
+ test_char("'\"'", '"');
+ test_char("'\\u{1F415}'", '\u{1F415}');
+}
+
+#[test]
+fn ints() {
+ fn test_int(s: &str, value: u64, suffix: &str) {
+ match lit(s) {
+ Lit::Int(lit) => {
+ assert_eq!(lit.base10_digits().parse::<u64>().unwrap(), value);
+ assert_eq!(lit.suffix(), suffix);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_int(&again, value, suffix);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_int("5", 5, "");
+ test_int("5u32", 5, "u32");
+ test_int("5_0", 50, "");
+ test_int("5_____0_____", 50, "");
+ test_int("0x7f", 127, "");
+ test_int("0x7F", 127, "");
+ test_int("0b1001", 9, "");
+ test_int("0o73", 59, "");
+ test_int("0x7Fu8", 127, "u8");
+ test_int("0b1001i8", 9, "i8");
+ test_int("0o73u32", 59, "u32");
+ test_int("0x__7___f_", 127, "");
+ test_int("0x__7___F_", 127, "");
+ test_int("0b_1_0__01", 9, "");
+ test_int("0o_7__3", 59, "");
+ test_int("0x_7F__u8", 127, "u8");
+ test_int("0b__10__0_1i8", 9, "i8");
+ test_int("0o__7__________________3u32", 59, "u32");
+}
+
+#[test]
+fn floats() {
+ #[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
+ fn test_float(s: &str, value: f64, suffix: &str) {
+ match lit(s) {
+ Lit::Float(lit) => {
+ assert_eq!(lit.base10_digits().parse::<f64>().unwrap(), value);
+ assert_eq!(lit.suffix(), suffix);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_float(&again, value, suffix);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_float("5.5", 5.5, "");
+ test_float("5.5E12", 5.5e12, "");
+ test_float("5.5e12", 5.5e12, "");
+ test_float("1.0__3e-12", 1.03e-12, "");
+ test_float("1.03e+12", 1.03e12, "");
+}
diff --git a/syn/tests/test_meta.rs b/syn/tests/test_meta.rs
new file mode 100644
index 0000000..618296e
--- /dev/null
+++ b/syn/tests/test_meta.rs
@@ -0,0 +1,341 @@
+mod features;
+
+#[macro_use]
+mod macros;
+
+use syn::{Meta, MetaList, MetaNameValue, NestedMeta};
+
+#[test]
+fn test_parse_meta_item_word() {
+ let input = "hello";
+
+ snapshot!(input as Meta, @r###"
+ Path(Path {
+ segments: [
+ PathSegment {
+ ident: "hello",
+ arguments: None,
+ },
+ ],
+ })
+ "###);
+}
+
+#[test]
+fn test_parse_meta_name_value() {
+ let input = "foo = 5";
+ let (inner, meta) = (input, input);
+
+ snapshot!(inner as MetaNameValue, @r###"
+ MetaNameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }
+ "###);
+
+ snapshot!(meta as Meta, @r###"
+ Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }
+ "###);
+
+ assert_eq!(meta, inner.into());
+}
+
+#[test]
+fn test_parse_meta_name_value_with_keyword() {
+ let input = "static = 5";
+ let (inner, meta) = (input, input);
+
+ snapshot!(inner as MetaNameValue, @r###"
+ MetaNameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "static",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }
+ "###);
+
+ snapshot!(meta as Meta, @r###"
+ Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "static",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }
+ "###);
+
+ assert_eq!(meta, inner.into());
+}
+
+#[test]
+fn test_parse_meta_name_value_with_bool() {
+ let input = "true = 5";
+ let (inner, meta) = (input, input);
+
+ snapshot!(inner as MetaNameValue, @r###"
+ MetaNameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "true",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }
+ "###);
+
+ snapshot!(meta as Meta, @r###"
+ Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "true",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }
+ "###);
+
+ assert_eq!(meta, inner.into());
+}
+
+#[test]
+fn test_parse_meta_item_list_lit() {
+ let input = "foo(5)";
+ let (inner, meta) = (input, input);
+
+ snapshot!(inner as MetaList, @r###"
+ MetaList {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Lit(5),
+ ],
+ }
+ "###);
+
+ snapshot!(meta as Meta, @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Lit(5),
+ ],
+ }
+ "###);
+
+ assert_eq!(meta, inner.into());
+}
+
+#[test]
+fn test_parse_meta_item_multiple() {
+ let input = "foo(word, name = 5, list(name2 = 6), word2)";
+ let (inner, meta) = (input, input);
+
+ snapshot!(inner as MetaList, @r###"
+ MetaList {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "word",
+ arguments: None,
+ },
+ ],
+ })),
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "name",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }),
+ Meta(Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "list",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "name2",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 6,
+ }),
+ ],
+ }),
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "word2",
+ arguments: None,
+ },
+ ],
+ })),
+ ],
+ }
+ "###);
+
+ snapshot!(meta as Meta, @r###"
+ Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "foo",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "word",
+ arguments: None,
+ },
+ ],
+ })),
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "name",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 5,
+ }),
+ Meta(Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "list",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "name2",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 6,
+ }),
+ ],
+ }),
+ Meta(Path(Path {
+ segments: [
+ PathSegment {
+ ident: "word2",
+ arguments: None,
+ },
+ ],
+ })),
+ ],
+ }
+ "###);
+
+ assert_eq!(meta, inner.into());
+}
+
+#[test]
+fn test_parse_nested_meta() {
+ let input = "5";
+ snapshot!(input as NestedMeta, @"Lit(5)");
+
+ let input = "list(name2 = 6)";
+ snapshot!(input as NestedMeta, @r###"
+ Meta(Meta::List {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "list",
+ arguments: None,
+ },
+ ],
+ },
+ nested: [
+ Meta(Meta::NameValue {
+ path: Path {
+ segments: [
+ PathSegment {
+ ident: "name2",
+ arguments: None,
+ },
+ ],
+ },
+ lit: 6,
+ }),
+ ],
+ })
+ "###);
+}
diff --git a/syn/tests/test_parse_buffer.rs b/syn/tests/test_parse_buffer.rs
new file mode 100644
index 0000000..d3f10c0
--- /dev/null
+++ b/syn/tests/test_parse_buffer.rs
@@ -0,0 +1,53 @@
+use syn::parenthesized;
+use syn::parse::{discouraged::Speculative, Parse, ParseStream, Parser, Result};
+
+#[test]
+#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
+fn smuggled_speculative_cursor_between_sources() {
+ struct BreakRules;
+ impl Parse for BreakRules {
+ fn parse(input1: ParseStream) -> Result<Self> {
+ let nested = |input2: ParseStream| {
+ input1.advance_to(&input2);
+ Ok(Self)
+ };
+ nested.parse_str("")
+ }
+ }
+
+ syn::parse_str::<BreakRules>("").unwrap();
+}
+
+#[test]
+#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
+fn smuggled_speculative_cursor_between_brackets() {
+ struct BreakRules;
+ impl Parse for BreakRules {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let a;
+ let b;
+ parenthesized!(a in input);
+ parenthesized!(b in input);
+ a.advance_to(&b);
+ Ok(Self)
+ }
+ }
+
+ syn::parse_str::<BreakRules>("()()").unwrap();
+}
+
+#[test]
+#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
+fn smuggled_speculative_cursor_into_brackets() {
+ struct BreakRules;
+ impl Parse for BreakRules {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let a;
+ parenthesized!(a in input);
+ input.advance_to(&a);
+ Ok(Self)
+ }
+ }
+
+ syn::parse_str::<BreakRules>("()").unwrap();
+}
diff --git a/syn/tests/test_pat.rs b/syn/tests/test_pat.rs
new file mode 100644
index 0000000..cce4b80
--- /dev/null
+++ b/syn/tests/test_pat.rs
@@ -0,0 +1,20 @@
+mod features;
+
+use quote::quote;
+use syn::Pat;
+
+#[test]
+fn test_pat_ident() {
+ match syn::parse2(quote!(self)).unwrap() {
+ Pat::Ident(_) => (),
+ value => panic!("expected PatIdent, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_pat_path() {
+ match syn::parse2(quote!(self::CONST)).unwrap() {
+ Pat::Path(_) => (),
+ value => panic!("expected PatPath, got {:?}", value),
+ }
+}
diff --git a/syn/tests/test_precedence.rs b/syn/tests/test_precedence.rs
new file mode 100644
index 0000000..3529c06
--- /dev/null
+++ b/syn/tests/test_precedence.rs
@@ -0,0 +1,394 @@
+#![cfg(not(syn_disable_nightly_tests))]
+#![recursion_limit = "1024"]
+#![feature(rustc_private)]
+
+//! The tests in this module do the following:
+//!
+//! 1. Parse a given expression in both `syn` and `libsyntax`.
+//! 2. Fold over the expression adding brackets around each subexpression (with
+//! some complications - see the `syn_brackets` and `libsyntax_brackets`
+//! methods).
+//! 3. Serialize the `syn` expression back into a string, and re-parse it with
+//! `libsyntax`.
+//! 4. Respan all of the expressions, replacing the spans with the default
+//! spans.
+//! 5. Compare the expressions with one another, if they are not equal fail.
+
+extern crate rustc_data_structures;
+extern crate rustc_span;
+extern crate syntax;
+
+mod features;
+
+use quote::quote;
+use rayon::iter::{IntoParallelIterator, ParallelIterator};
+use regex::Regex;
+use rustc_span::edition::Edition;
+use syntax::ast;
+use syntax::ptr::P;
+use walkdir::{DirEntry, WalkDir};
+
+use std::fs::File;
+use std::io::Read;
+use std::process;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+use common::eq::SpanlessEq;
+use common::parse;
+
+#[macro_use]
+mod macros;
+
+#[allow(dead_code)]
+mod common;
+
+mod repo;
+
+/// Test some pre-set expressions chosen by us.
+#[test]
+fn test_simple_precedence() {
+ const EXPRS: &[&str] = &[
+ "1 + 2 * 3 + 4",
+ "1 + 2 * ( 3 + 4 )",
+ "{ for i in r { } *some_ptr += 1; }",
+ "{ loop { break 5; } }",
+ "{ if true { () }.mthd() }",
+ "{ for i in unsafe { 20 } { } }",
+ ];
+
+ let mut failed = 0;
+
+ for input in EXPRS {
+ let expr = if let Some(expr) = parse::syn_expr(input) {
+ expr
+ } else {
+ failed += 1;
+ continue;
+ };
+
+ let pf = match test_expressions(vec![expr]) {
+ (1, 0) => "passed",
+ (0, 1) => {
+ failed += 1;
+ "failed"
+ }
+ _ => unreachable!(),
+ };
+ errorf!("=== {}: {}\n", input, pf);
+ }
+
+ if failed > 0 {
+ panic!("Failed {} tests", failed);
+ }
+}
+
+/// Test expressions from rustc, like in `test_round_trip`.
+#[test]
+fn test_rustc_precedence() {
+ repo::clone_rust();
+ let abort_after = common::abort_after();
+ if abort_after == 0 {
+ panic!("Skipping all precedence tests");
+ }
+
+ let passed = AtomicUsize::new(0);
+ let failed = AtomicUsize::new(0);
+
+ // 2018 edition is hard
+ let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();
+
+ WalkDir::new("tests/rust")
+ .sort_by(|a, b| a.file_name().cmp(b.file_name()))
+ .into_iter()
+ .filter_entry(repo::base_dir_filter)
+ .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
+ .unwrap()
+ .into_par_iter()
+ .for_each(|entry| {
+ let path = entry.path();
+ if path.is_dir() {
+ return;
+ }
+
+ // Our version of `libsyntax` can't parse this tests
+ if path
+ .to_str()
+ .unwrap()
+ .ends_with("optional_comma_in_match_arm.rs")
+ {
+ return;
+ }
+
+ let mut file = File::open(path).unwrap();
+ let mut content = String::new();
+ file.read_to_string(&mut content).unwrap();
+ let content = edition_regex.replace_all(&content, "_$0");
+
+ let (l_passed, l_failed) = match syn::parse_file(&content) {
+ Ok(file) => {
+ let exprs = collect_exprs(file);
+ test_expressions(exprs)
+ }
+ Err(msg) => {
+ errorf!("syn failed to parse\n{:?}\n", msg);
+ (0, 1)
+ }
+ };
+
+ errorf!(
+ "=== {}: {} passed | {} failed\n",
+ path.display(),
+ l_passed,
+ l_failed
+ );
+
+ passed.fetch_add(l_passed, Ordering::SeqCst);
+ let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);
+
+ if prev_failed + l_failed >= abort_after {
+ process::exit(1);
+ }
+ });
+
+ let passed = passed.load(Ordering::SeqCst);
+ let failed = failed.load(Ordering::SeqCst);
+
+ errorf!("\n===== Precedence Test Results =====\n");
+ errorf!("{} passed | {} failed\n", passed, failed);
+
+ if failed > 0 {
+ panic!("{} failures", failed);
+ }
+}
+
+fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
+ let mut passed = 0;
+ let mut failed = 0;
+
+ syntax::with_globals(Edition::Edition2018, || {
+ for expr in exprs {
+ let raw = quote!(#expr).to_string();
+
+ let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
+ e
+ } else {
+ failed += 1;
+ errorf!("\nFAIL - libsyntax failed to parse raw\n");
+ continue;
+ };
+
+ let syn_expr = syn_brackets(expr);
+ let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
+ e
+ } else {
+ failed += 1;
+ errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
+ continue;
+ };
+
+ if SpanlessEq::eq(&syn_ast, &libsyntax_ast) {
+ passed += 1;
+ } else {
+ failed += 1;
+ errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
+ }
+ }
+ });
+
+ (passed, failed)
+}
+
+fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
+ parse::libsyntax_expr(input).and_then(libsyntax_brackets)
+}
+
+/// Wrap every expression which is not already wrapped in parens with parens, to
+/// reveal the precidence of the parsed expressions, and produce a stringified
+/// form of the resulting expression.
+///
+/// This method operates on libsyntax objects.
+fn libsyntax_brackets(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
+ use rustc_data_structures::thin_vec::ThinVec;
+ use rustc_span::DUMMY_SP;
+ use std::mem;
+ use syntax::ast::{Block, Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
+ use syntax::mut_visit::MutVisitor;
+ use syntax::util::map_in_place::MapInPlace;
+
+ struct BracketsVisitor {
+ failed: bool,
+ };
+
+ fn flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> Vec<Field> {
+ if f.is_shorthand {
+ noop_visit_expr(&mut f.expr, vis);
+ } else {
+ vis.visit_expr(&mut f.expr);
+ }
+ vec![f]
+ }
+
+ fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
+ let kind = match stmt.kind {
+ // Don't wrap toplevel expressions in statements.
+ StmtKind::Expr(mut e) => {
+ noop_visit_expr(&mut e, vis);
+ StmtKind::Expr(e)
+ }
+ StmtKind::Semi(mut e) => {
+ noop_visit_expr(&mut e, vis);
+ StmtKind::Semi(e)
+ }
+ s => s,
+ };
+
+ vec![Stmt { kind, ..stmt }]
+ }
+
+ fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
+ use syntax::mut_visit::{noop_visit_expr, visit_opt, visit_thin_attrs};
+ match &mut e.kind {
+ ExprKind::Struct(path, fields, expr) => {
+ vis.visit_path(path);
+ fields.flat_map_in_place(|field| flat_map_field(field, vis));
+ visit_opt(expr, |expr| vis.visit_expr(expr));
+ vis.visit_id(&mut e.id);
+ vis.visit_span(&mut e.span);
+ visit_thin_attrs(&mut e.attrs, vis);
+ }
+ _ => noop_visit_expr(e, vis),
+ }
+ }
+
+ impl MutVisitor for BracketsVisitor {
+ fn visit_expr(&mut self, e: &mut P<Expr>) {
+ noop_visit_expr(e, self);
+ match e.kind {
+ ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
+ _ => {
+ let inner = mem::replace(
+ e,
+ P(Expr {
+ id: ast::DUMMY_NODE_ID,
+ kind: ExprKind::Err,
+ span: DUMMY_SP,
+ attrs: ThinVec::new(),
+ }),
+ );
+ e.kind = ExprKind::Paren(inner);
+ }
+ }
+ }
+
+ fn visit_block(&mut self, block: &mut P<Block>) {
+ self.visit_id(&mut block.id);
+ block
+ .stmts
+ .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
+ self.visit_span(&mut block.span);
+ }
+
+ // We don't want to look at expressions that might appear in patterns or
+ // types yet. We'll look into comparing those in the future. For now
+ // focus on expressions appearing in other places.
+ fn visit_pat(&mut self, pat: &mut P<Pat>) {
+ let _ = pat;
+ }
+
+ fn visit_ty(&mut self, ty: &mut P<Ty>) {
+ let _ = ty;
+ }
+
+ fn visit_mac(&mut self, mac: &mut Mac) {
+ // By default when folding over macros, libsyntax panics. This is
+ // because it's usually not what you want, you want to run after
+ // macro expansion. We do want to do that (syn doesn't do macro
+ // expansion), so we implement visit_mac to just return the macro
+ // unchanged.
+ let _ = mac;
+ }
+ }
+
+ let mut folder = BracketsVisitor { failed: false };
+ folder.visit_expr(&mut libsyntax_expr);
+ if folder.failed {
+ None
+ } else {
+ Some(libsyntax_expr)
+ }
+}
+
+/// Wrap every expression which is not already wrapped in parens with parens, to
+/// reveal the precedence of the parsed expressions, and produce a stringified
+/// form of the resulting expression.
+fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
+ use syn::fold::*;
+ use syn::*;
+
+ struct ParenthesizeEveryExpr;
+ impl Fold for ParenthesizeEveryExpr {
+ fn fold_expr(&mut self, expr: Expr) -> Expr {
+ match expr {
+ Expr::Group(_) => unreachable!(),
+ Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
+ fold_expr(self, expr)
+ }
+ _ => Expr::Paren(ExprParen {
+ attrs: Vec::new(),
+ expr: Box::new(fold_expr(self, expr)),
+ paren_token: token::Paren::default(),
+ }),
+ }
+ }
+
+ fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
+ match stmt {
+ // Don't wrap toplevel expressions in statements.
+ Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
+ Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
+ s => s,
+ }
+ }
+
+ // We don't want to look at expressions that might appear in patterns or
+ // types yet. We'll look into comparing those in the future. For now
+ // focus on expressions appearing in other places.
+ fn fold_pat(&mut self, pat: Pat) -> Pat {
+ pat
+ }
+
+ fn fold_type(&mut self, ty: Type) -> Type {
+ ty
+ }
+ }
+
+ let mut folder = ParenthesizeEveryExpr;
+ folder.fold_expr(syn_expr)
+}
+
+/// Walk through a crate collecting all expressions we can find in it.
+fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
+ use syn::fold::*;
+ use syn::punctuated::Punctuated;
+ use syn::*;
+
+ struct CollectExprs(Vec<Expr>);
+ impl Fold for CollectExprs {
+ fn fold_expr(&mut self, expr: Expr) -> Expr {
+ match expr {
+ Expr::Verbatim(tokens) if tokens.is_empty() => {}
+ _ => self.0.push(expr),
+ }
+
+ Expr::Tuple(ExprTuple {
+ attrs: vec![],
+ elems: Punctuated::new(),
+ paren_token: token::Paren::default(),
+ })
+ }
+ }
+
+ let mut folder = CollectExprs(vec![]);
+ folder.fold_file(file);
+ folder.0
+}
diff --git a/syn/tests/test_receiver.rs b/syn/tests/test_receiver.rs
new file mode 100644
index 0000000..168db8f
--- /dev/null
+++ b/syn/tests/test_receiver.rs
@@ -0,0 +1,109 @@
+mod features;
+
+use syn::{FnArg, Receiver, TraitItemMethod};
+
+#[test]
+fn test_by_value() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_value(self: Self););
+ match sig.receiver() {
+ Some(FnArg::Typed(_)) => (),
+ value => panic!("expected FnArg::Typed, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_by_mut_value() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_mut(mut self: Self););
+ match sig.receiver() {
+ Some(FnArg::Typed(_)) => (),
+ value => panic!("expected FnArg::Typed, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_by_ref() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_ref(self: &Self););
+ match sig.receiver() {
+ Some(FnArg::Typed(_)) => (),
+ value => panic!("expected FnArg::Typed, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_by_box() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_box(self: Box<Self>););
+ match sig.receiver() {
+ Some(FnArg::Typed(_)) => (),
+ value => panic!("expected FnArg::Typed, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_by_pin() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_pin(self: Pin<Self>););
+ match sig.receiver() {
+ Some(FnArg::Typed(_)) => (),
+ value => panic!("expected FnArg::Typed, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_explicit_type() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn explicit_type(self: Pin<MyType>););
+ match sig.receiver() {
+ Some(FnArg::Typed(_)) => (),
+ value => panic!("expected FnArg::Typed, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_value_shorthand() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn value_shorthand(self););
+ match sig.receiver() {
+ Some(FnArg::Receiver(Receiver {
+ reference: None,
+ mutability: None,
+ ..
+ })) => (),
+ value => panic!("expected FnArg::Receiver without ref/mut, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_mut_value_shorthand() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn mut_value_shorthand(mut self););
+ match sig.receiver() {
+ Some(FnArg::Receiver(Receiver {
+ reference: None,
+ mutability: Some(_),
+ ..
+ })) => (),
+ value => panic!("expected FnArg::Receiver with mut, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_ref_shorthand() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn ref_shorthand(&self););
+ match sig.receiver() {
+ Some(FnArg::Receiver(Receiver {
+ reference: Some(_),
+ mutability: None,
+ ..
+ })) => (),
+ value => panic!("expected FnArg::Receiver with ref, got {:?}", value),
+ }
+}
+
+#[test]
+fn test_ref_mut_shorthand() {
+ let TraitItemMethod { sig, .. } = syn::parse_quote!(fn ref_mut_shorthand(&mut self););
+ match sig.receiver() {
+ Some(FnArg::Receiver(Receiver {
+ reference: Some(_),
+ mutability: Some(_),
+ ..
+ })) => (),
+ value => panic!("expected FnArg::Receiver with ref+mut, got {:?}", value),
+ }
+}
diff --git a/syn/tests/test_round_trip.rs b/syn/tests/test_round_trip.rs
new file mode 100644
index 0000000..435bd6a
--- /dev/null
+++ b/syn/tests/test_round_trip.rs
@@ -0,0 +1,151 @@
+#![cfg(not(syn_disable_nightly_tests))]
+#![recursion_limit = "1024"]
+#![feature(rustc_private)]
+
+extern crate rustc_expand;
+extern crate rustc_parse as parse;
+extern crate rustc_span;
+extern crate syntax;
+
+mod features;
+
+use quote::quote;
+use rayon::iter::{IntoParallelIterator, ParallelIterator};
+use rustc_span::edition::Edition;
+use rustc_span::FileName;
+use syntax::ast;
+use syntax::errors::PResult;
+use syntax::sess::ParseSess;
+use syntax::source_map::FilePathMapping;
+use walkdir::{DirEntry, WalkDir};
+
+use std::fs::File;
+use std::io::Read;
+use std::panic;
+use std::process;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::time::Instant;
+
+#[macro_use]
+mod macros;
+
+#[allow(dead_code)]
+mod common;
+
+mod repo;
+
+use common::eq::SpanlessEq;
+
+#[test]
+fn test_round_trip() {
+ repo::clone_rust();
+ let abort_after = common::abort_after();
+ if abort_after == 0 {
+ panic!("Skipping all round_trip tests");
+ }
+
+ let failed = AtomicUsize::new(0);
+
+ WalkDir::new("tests/rust")
+ .sort_by(|a, b| a.file_name().cmp(b.file_name()))
+ .into_iter()
+ .filter_entry(repo::base_dir_filter)
+ .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
+ .unwrap()
+ .into_par_iter()
+ .for_each(|entry| {
+ let path = entry.path();
+ if path.is_dir() {
+ return;
+ }
+
+ let mut file = File::open(path).unwrap();
+ let mut content = String::new();
+ file.read_to_string(&mut content).unwrap();
+
+ let start = Instant::now();
+ let (krate, elapsed) = match syn::parse_file(&content) {
+ Ok(krate) => (krate, start.elapsed()),
+ Err(msg) => {
+ errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg);
+ let prev_failed = failed.fetch_add(1, Ordering::SeqCst);
+ if prev_failed + 1 >= abort_after {
+ process::exit(1);
+ }
+ return;
+ }
+ };
+ let back = quote!(#krate).to_string();
+
+ let equal = panic::catch_unwind(|| {
+ syntax::with_globals(Edition::Edition2018, || {
+ let sess = ParseSess::new(FilePathMapping::empty());
+ let before = match libsyntax_parse(content, &sess) {
+ Ok(before) => before,
+ Err(mut diagnostic) => {
+ diagnostic.cancel();
+ if diagnostic
+ .message()
+ .starts_with("file not found for module")
+ {
+ errorf!("=== {}: ignore\n", path.display());
+ } else {
+ errorf!(
+ "=== {}: ignore - libsyntax failed to parse original content: {}\n",
+ path.display(),
+ diagnostic.message()
+ );
+ }
+ return true;
+ }
+ };
+ let after = match libsyntax_parse(back, &sess) {
+ Ok(after) => after,
+ Err(mut diagnostic) => {
+ errorf!("=== {}: libsyntax failed to parse", path.display());
+ diagnostic.emit();
+ return false;
+ }
+ };
+
+ if SpanlessEq::eq(&before, &after) {
+ errorf!(
+ "=== {}: pass in {}ms\n",
+ path.display(),
+ elapsed.as_secs() * 1000
+ + u64::from(elapsed.subsec_nanos()) / 1_000_000
+ );
+ true
+ } else {
+ errorf!(
+ "=== {}: FAIL\nbefore: {:#?}\nafter: {:#?}\n",
+ path.display(),
+ before,
+ after,
+ );
+ false
+ }
+ })
+ });
+ match equal {
+ Err(_) => errorf!("=== {}: ignoring libsyntax panic\n", path.display()),
+ Ok(true) => {}
+ Ok(false) => {
+ let prev_failed = failed.fetch_add(1, Ordering::SeqCst);
+ if prev_failed + 1 >= abort_after {
+ process::exit(1);
+ }
+ }
+ }
+ });
+
+ let failed = failed.load(Ordering::SeqCst);
+ if failed > 0 {
+ panic!("{} failures", failed);
+ }
+}
+
+fn libsyntax_parse(content: String, sess: &ParseSess) -> PResult<ast::Crate> {
+ let name = FileName::Custom("test_round_trip".to_string());
+ parse::parse_crate_from_source_str(name, content, sess)
+}
diff --git a/syn/tests/test_should_parse.rs b/syn/tests/test_should_parse.rs
new file mode 100644
index 0000000..d4f7ac3
--- /dev/null
+++ b/syn/tests/test_should_parse.rs
@@ -0,0 +1,47 @@
+mod features;
+
+macro_rules! should_parse {
+ ($name:ident, { $($in:tt)* }) => {
+ #[test]
+ fn $name() {
+ // Make sure we can parse the file!
+ syn::parse_file(stringify!($($in)*)).unwrap();
+ }
+ }
+}
+
+should_parse!(generic_associated_type, {
+ impl Foo {
+ type Item = &'a i32;
+ fn foo<'a>(&'a self) -> Self::Item<'a> {}
+ }
+});
+
+#[rustfmt::skip]
+should_parse!(const_generics_use, {
+ type X = Foo<5>;
+ type Y = Foo<"foo">;
+ type Z = Foo<X>;
+ type W = Foo<{ X + 10 }>;
+});
+
+should_parse!(trailing_plus_type, {
+ type A = Box<Foo>;
+ type A = Box<Foo + 'a>;
+ type A = Box<'a + Foo>;
+});
+
+should_parse!(generic_associated_type_where, {
+ trait Foo {
+ type Item;
+ fn foo<T>(&self, t: T) -> Self::Item<T>;
+ }
+});
+
+should_parse!(match_with_block_expr, {
+ fn main() {
+ match false {
+ _ => {}.a(),
+ }
+ }
+});
diff --git a/syn/tests/test_size.rs b/syn/tests/test_size.rs
new file mode 100644
index 0000000..386d4df
--- /dev/null
+++ b/syn/tests/test_size.rs
@@ -0,0 +1,31 @@
+#![cfg(target_pointer_width = "64")]
+
+mod features;
+
+use std::mem;
+use syn::*;
+
+#[test]
+fn test_expr_size() {
+ assert_eq!(mem::size_of::<Expr>(), 280);
+}
+
+#[test]
+fn test_item_size() {
+ assert_eq!(mem::size_of::<Item>(), 344);
+}
+
+#[test]
+fn test_type_size() {
+ assert_eq!(mem::size_of::<Type>(), 304);
+}
+
+#[test]
+fn test_pat_size() {
+ assert_eq!(mem::size_of::<Pat>(), 144);
+}
+
+#[test]
+fn test_lit_size() {
+ assert_eq!(mem::size_of::<Lit>(), 40);
+}
diff --git a/syn/tests/test_token_trees.rs b/syn/tests/test_token_trees.rs
new file mode 100644
index 0000000..5d7610b
--- /dev/null
+++ b/syn/tests/test_token_trees.rs
@@ -0,0 +1,28 @@
+mod features;
+
+#[macro_use]
+mod macros;
+
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::Lit;
+
+#[test]
+fn test_struct() {
+ let input = "
+ #[derive(Debug, Clone)]
+ pub struct Item {
+ pub ident: Ident,
+ pub attrs: Vec<Attribute>,
+ }
+ ";
+
+ snapshot!(input as TokenStream, @"`# [ derive ( Debug , Clone ) ] pub struct Item { pub ident : Ident , pub attrs : Vec < Attribute >, }`");
+}
+
+#[test]
+fn test_literal_mangling() {
+ let code = "0_4";
+ let parsed: Lit = syn::parse_str(code).unwrap();
+ assert_eq!(code, quote!(#parsed).to_string());
+}
diff --git a/syn/tests/test_visibility.rs b/syn/tests/test_visibility.rs
new file mode 100644
index 0000000..21c49c9
--- /dev/null
+++ b/syn/tests/test_visibility.rs
@@ -0,0 +1,99 @@
+mod features;
+
+use proc_macro2::TokenStream;
+use syn::parse::{Parse, ParseStream};
+use syn::{Result, Visibility};
+
+#[derive(Debug)]
+struct VisRest {
+ vis: Visibility,
+ rest: TokenStream,
+}
+
+impl Parse for VisRest {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(VisRest {
+ vis: input.parse()?,
+ rest: input.parse()?,
+ })
+ }
+}
+
+macro_rules! assert_vis_parse {
+ ($input:expr, Ok($p:pat)) => {
+ assert_vis_parse!($input, Ok($p) + "");
+ };
+
+ ($input:expr, Ok($p:pat) + $rest:expr) => {
+ let expected = $rest.parse::<TokenStream>().unwrap();
+ let parse: VisRest = syn::parse_str($input).unwrap();
+
+ match parse.vis {
+ $p => {}
+ _ => panic!("Expected {}, got {:?}", stringify!($p), parse.vis),
+ }
+
+ // NOTE: Round-trips through `to_string` to avoid potential whitespace
+ // diffs.
+ assert_eq!(parse.rest.to_string(), expected.to_string());
+ };
+
+ ($input:expr, Err) => {
+ syn::parse2::<VisRest>($input.parse().unwrap()).unwrap_err();
+ };
+}
+
+#[test]
+fn test_pub() {
+ assert_vis_parse!("pub", Ok(Visibility::Public(_)));
+}
+
+#[test]
+fn test_crate() {
+ assert_vis_parse!("crate", Ok(Visibility::Crate(_)));
+}
+
+#[test]
+fn test_inherited() {
+ assert_vis_parse!("", Ok(Visibility::Inherited));
+}
+
+#[test]
+fn test_in() {
+ assert_vis_parse!("pub(in foo::bar)", Ok(Visibility::Restricted(_)));
+}
+
+#[test]
+fn test_pub_crate() {
+ assert_vis_parse!("pub(crate)", Ok(Visibility::Restricted(_)));
+}
+
+#[test]
+fn test_pub_self() {
+ assert_vis_parse!("pub(self)", Ok(Visibility::Restricted(_)));
+}
+
+#[test]
+fn test_pub_super() {
+ assert_vis_parse!("pub(super)", Ok(Visibility::Restricted(_)));
+}
+
+#[test]
+fn test_missing_in() {
+ assert_vis_parse!("pub(foo::bar)", Ok(Visibility::Public(_)) + "(foo::bar)");
+}
+
+#[test]
+fn test_missing_in_path() {
+ assert_vis_parse!("pub(in)", Err);
+}
+
+#[test]
+fn test_crate_path() {
+ assert_vis_parse!("pub(crate::A, crate::B)", Ok(Visibility::Public(_)) + "(crate::A, crate::B)");
+}
+
+#[test]
+fn test_junk_after_in() {
+ assert_vis_parse!("pub(in some::path @@garbage)", Err);
+}
diff --git a/syn/tests/zzz_stable.rs b/syn/tests/zzz_stable.rs
new file mode 100644
index 0000000..6c768f2
--- /dev/null
+++ b/syn/tests/zzz_stable.rs
@@ -0,0 +1,33 @@
+#![cfg(syn_disable_nightly_tests)]
+
+use std::io::{self, Write};
+use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
+
+const MSG: &str = "\
+‖
+‖ WARNING:
+‖ This is not a nightly compiler so not all tests were able to
+‖ run. Syn includes tests that compare Syn's parser against the
+‖ compiler's parser, which requires access to unstable libsyntax
+‖ data structures and a nightly compiler.
+‖
+";
+
+#[test]
+fn notice() -> io::Result<()> {
+ let header = "WARNING";
+ let index_of_header = MSG.find(header).unwrap();
+ let before = &MSG[..index_of_header];
+ let after = &MSG[index_of_header + header.len()..];
+
+ let mut stderr = StandardStream::stderr(ColorChoice::Auto);
+ stderr.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?;
+ write!(&mut stderr, "{}", before)?;
+ stderr.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?;
+ write!(&mut stderr, "{}", header)?;
+ stderr.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?;
+ write!(&mut stderr, "{}", after)?;
+ stderr.reset()?;
+
+ Ok(())
+}
diff --git a/textwrap/.appveyor.yml b/textwrap/.appveyor.yml
new file mode 100644
index 0000000..3555d73
--- /dev/null
+++ b/textwrap/.appveyor.yml
@@ -0,0 +1,23 @@
+environment:
+ matrix:
+ - TOOLCHAIN: stable
+ - TOOLCHAIN: nightly
+
+matrix:
+ allow_failures:
+ - TOOLCHAIN: nightly
+
+install:
+ - ps: Start-FileDownload 'https://static.rust-lang.org/rustup/dist/i686-pc-windows-gnu/rustup-init.exe'
+ - rustup-init.exe -y --default-toolchain %TOOLCHAIN%
+ - set PATH=%PATH%;%USERPROFILE%\.cargo\bin
+
+build_script:
+ - cargo build --verbose --all-features
+
+test_script:
+ - cargo test --verbose --all-features
+
+cache:
+ - '%USERPROFILE%\.cargo'
+ - target
diff --git a/textwrap/.circleci/config.yml b/textwrap/.circleci/config.yml
new file mode 100644
index 0000000..4f928a6
--- /dev/null
+++ b/textwrap/.circleci/config.yml
@@ -0,0 +1,13 @@
+version: 2
+jobs:
+ build:
+ docker:
+ - image: xd009642/tarpaulin
+ steps:
+ - checkout
+ - run:
+ name: Generate coverage report
+ command: cargo tarpaulin --out Xml --all-features
+ - run:
+ name: Upload to codecov.io
+ command: bash <(curl -s https://codecov.io/bash) -Z -f cobertura.xml
diff --git a/textwrap/.codecov.yml b/textwrap/.codecov.yml
new file mode 100644
index 0000000..a9b0bd2
--- /dev/null
+++ b/textwrap/.codecov.yml
@@ -0,0 +1,13 @@
+codecov:
+ # Do not wait for these CI providers since they will not upload any
+ # coverage reports.
+ ci:
+ - !appveyor
+ - !travis
+
+coverage:
+ status:
+ project:
+ default:
+ # Allow a 5% drop in overall project coverage on a PR.
+ threshold: 5%
diff --git a/textwrap/.dir-locals.el b/textwrap/.dir-locals.el
new file mode 100644
index 0000000..0faa664
--- /dev/null
+++ b/textwrap/.dir-locals.el
@@ -0,0 +1,3 @@
+((nil
+ (bug-reference-bug-regexp . "#\\(?2:[0-9]+\\)")
+ (bug-reference-url-format . "https://github.com/mgeisler/textwrap/issues/%s")))
diff --git a/textwrap/.gitignore b/textwrap/.gitignore
new file mode 100644
index 0000000..6513848
--- /dev/null
+++ b/textwrap/.gitignore
@@ -0,0 +1,5 @@
+Cargo.lock
+target/
+
+*~
+*.orig
diff --git a/textwrap/.travis.yml b/textwrap/.travis.yml
new file mode 100644
index 0000000..156418b
--- /dev/null
+++ b/textwrap/.travis.yml
@@ -0,0 +1,17 @@
+language: rust
+
+rust:
+ - stable
+ - beta
+ - nightly
+ - 1.22.0
+
+cache: cargo
+
+script:
+ - cargo build --verbose --all-features
+ - cargo test --verbose --all-features
+
+matrix:
+ allow_failures:
+ - rust: nightly
diff --git a/textwrap/Cargo.toml b/textwrap/Cargo.toml
new file mode 100644
index 0000000..9d82ca5
--- /dev/null
+++ b/textwrap/Cargo.toml
@@ -0,0 +1,38 @@
+[package]
+name = "textwrap"
+version = "0.11.0"
+authors = ["Martin Geisler <martin@geisler.net>"]
+description = """
+Textwrap is a small library for word wrapping, indenting, and
+dedenting strings.
+
+You can use it to format strings (such as help and error messages) for
+display in commandline applications. It is designed to be efficient
+and handle Unicode characters correctly.
+"""
+documentation = "https://docs.rs/textwrap/"
+repository = "https://github.com/mgeisler/textwrap"
+readme = "README.md"
+keywords = ["text", "formatting", "wrap", "typesetting", "hyphenation"]
+categories = ["text-processing", "command-line-interface"]
+license = "MIT"
+exclude = [".dir-locals.el"]
+
+[package.metadata.docs.rs]
+all-features = true
+
+[badges]
+travis-ci = { repository = "mgeisler/textwrap" }
+appveyor = { repository = "mgeisler/textwrap" }
+codecov = { repository = "mgeisler/textwrap" }
+
+[dependencies]
+unicode-width = "0.1.3"
+term_size = { version = "0.3.0", optional = true }
+hyphenation = { version = "0.7.1", optional = true, features = ["embed_all"] }
+
+[dev-dependencies]
+lipsum = "0.6"
+rand = "0.6"
+rand_xorshift = "0.1"
+version-sync = "0.6"
diff --git a/textwrap/LICENSE b/textwrap/LICENSE
new file mode 100644
index 0000000..0d37ec3
--- /dev/null
+++ b/textwrap/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Martin Geisler
+
+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/textwrap/README.md b/textwrap/README.md
new file mode 100644
index 0000000..23a5439
--- /dev/null
+++ b/textwrap/README.md
@@ -0,0 +1,337 @@
+# Textwrap
+
+[![](https://img.shields.io/crates/v/textwrap.svg)][crates-io]
+[![](https://docs.rs/textwrap/badge.svg)][api-docs]
+[![](https://travis-ci.org/mgeisler/textwrap.svg?branch=master)][travis-ci]
+[![](https://ci.appveyor.com/api/projects/status/github/mgeisler/textwrap?branch=master&svg=true)][appveyor]
+[![](https://codecov.io/gh/mgeisler/textwrap/branch/master/graph/badge.svg)][codecov]
+
+Textwrap is a small Rust crate for word wrapping text. You can use it
+to format strings for display in commandline applications. The crate
+name and interface is inspired by
+the [Python textwrap module][py-textwrap].
+
+## Usage
+
+Add this to your `Cargo.toml`:
+```toml
+[dependencies]
+textwrap = "0.11"
+```
+
+and this to your crate root:
+```rust
+extern crate textwrap;
+```
+
+If you would like to have automatic hyphenation, specify the
+dependency as:
+```toml
+[dependencies]
+textwrap = { version = "0.11", features = ["hyphenation"] }
+```
+
+To conveniently wrap text at the current terminal width, enable the
+`term_size` feature:
+
+```toml
+[dependencies]
+textwrap = { version = "0.11", features = ["term_size"] }
+```
+
+## Documentation
+
+**[API documentation][api-docs]**
+
+## Getting Started
+
+Word wrapping single strings is easy using the `fill` function:
+```rust
+extern crate textwrap;
+use textwrap::fill;
+
+fn main() {
+ let text = "textwrap: a small library for wrapping text.";
+ println!("{}", fill(text, 18));
+}
+```
+The output is
+```
+textwrap: a small
+library for
+wrapping text.
+```
+
+With the `hyphenation` feature, you can get automatic hyphenation
+for [about 70 languages][patterns]. Your program must load and
+configure the hyphenation patterns to use:
+```rust
+extern crate hyphenation;
+extern crate textwrap;
+
+use hyphenation::{Language, Load, Standard};
+use textwrap::Wrapper;
+
+fn main() {
+ let hyphenator = Standard::from_embedded(Language::EnglishUS).unwrap();
+ let wrapper = Wrapper::with_splitter(18, hyphenator);
+ let text = "textwrap: a small library for wrapping text.";
+ println!("{}", wrapper.fill(text))
+}
+```
+
+The output now looks like this:
+```
+textwrap: a small
+library for wrap-
+ping text.
+```
+
+The hyphenation uses high-quality TeX hyphenation patterns.
+
+## Examples
+
+The library comes with some small example programs that shows various
+features.
+
+### Layout Example
+
+The `layout` example shows how a fixed example string is wrapped at
+different widths. Run the example with:
+
+```shell
+$ cargo run --features hyphenation --example layout
+```
+
+The program will use the following string:
+
+> Memory safety without garbage collection. Concurrency without data
+> races. Zero-cost abstractions.
+
+The string is wrapped at all widths between 15 and 60 columns. With
+narrow columns the output looks like this:
+
+```
+.--- Width: 15 ---.
+| Memory safety |
+| without garbage |
+| collection. |
+| Concurrency |
+| without data |
+| races. Zero- |
+| cost abstrac- |
+| tions. |
+.--- Width: 16 ----.
+| Memory safety |
+| without garbage |
+| collection. Con- |
+| currency without |
+| data races. Ze- |
+| ro-cost abstrac- |
+| tions. |
+```
+
+Later, longer lines are used and the output now looks like this:
+
+```
+.-------------------- Width: 49 --------------------.
+| Memory safety without garbage collection. Concur- |
+| rency without data races. Zero-cost abstractions. |
+.---------------------- Width: 53 ----------------------.
+| Memory safety without garbage collection. Concurrency |
+| without data races. Zero-cost abstractions. |
+.------------------------- Width: 59 -------------------------.
+| Memory safety without garbage collection. Concurrency with- |
+| out data races. Zero-cost abstractions. |
+```
+
+Notice how words are split at hyphens (such as "zero-cost") but also
+how words are hyphenated using automatic/machine hyphenation.
+
+### Terminal Width Example
+
+The `termwidth` example simply shows how the width can be set
+automatically to the current terminal width. Run it with this command:
+
+```
+$ cargo run --example termwidth
+```
+
+If you run it in a narrow terminal, you'll see output like this:
+```
+Formatted in within 60 columns:
+----
+Memory safety without garbage collection. Concurrency
+without data races. Zero-cost abstractions.
+----
+```
+
+If `stdout` is not connected to the terminal, the program will use a
+default of 80 columns for the width:
+
+```
+$ cargo run --example termwidth | cat
+Formatted in within 80 columns:
+----
+Memory safety without garbage collection. Concurrency without data races. Zero-
+cost abstractions.
+----
+```
+
+## Release History
+
+This section lists the largest changes per release.
+
+### Version 0.11.0 — December 9th, 2018
+
+Due to our dependencies bumping their minimum supported version of
+Rust, the minimum version of Rust we test against is now 1.22.0.
+
+* Merged [#141][issue-141]: Fix `dedent` handling of empty lines and
+ trailing newlines. Thanks @bbqsrc!
+* Fixed [#151][issue-151]: Release of version with hyphenation 0.7.
+
+### Version 0.10.0 — April 28th, 2018
+
+Due to our dependencies bumping their minimum supported version of
+Rust, the minimum version of Rust we test against is now 1.17.0.
+
+* Fixed [#99][issue-99]: Word broken even though it would fit on line.
+* Fixed [#107][issue-107]: Automatic hyphenation is off by one.
+* Fixed [#122][issue-122]: Take newlines into account when wrapping.
+* Fixed [#129][issue-129]: Panic on string with em-dash.
+
+### Version 0.9.0 — October 5th, 2017
+
+The dependency on `term_size` is now optional, and by default this
+feature is not enabled. This is a *breaking change* for users of
+`Wrapper::with_termwidth`. Enable the `term_size` feature to restore
+the old functionality.
+
+Added a regression test for the case where `width` is set to
+`usize::MAX`, thanks @Fraser999! All public structs now implement
+`Debug`, thanks @hcpl!
+
+* Fixed [#101][issue-101]: Make `term_size` an optional dependency.
+
+### Version 0.8.0 — September 4th, 2017
+
+The `Wrapper` stuct is now generic over the type of word splitter
+being used. This means less boxing and a nicer API. The
+`Wrapper::word_splitter` method has been removed. This is a *breaking
+API change* if you used the method to change the word splitter.
+
+The `Wrapper` struct has two new methods that will wrap the input text
+lazily: `Wrapper::wrap_iter` and `Wrapper::into_wrap_iter`. Use those
+if you will be iterating over the wrapped lines one by one.
+
+* Fixed [#59][issue-59]: `wrap` could return an iterator. Thanks
+ @hcpl!
+* Fixed [#81][issue-81]: Set `html_root_url`.
+
+### Version 0.7.0 — July 20th, 2017
+
+Version 0.7.0 changes the return type of `Wrapper::wrap` from
+`Vec<String>` to `Vec<Cow<'a, str>>`. This means that the output lines
+borrow data from the input string. This is a *breaking API change* if
+you relied on the exact return type of `Wrapper::wrap`. Callers of the
+`textwrap::fill` convenience function will see no breakage.
+
+The above change and other optimizations makes version 0.7.0 roughly
+15-30% faster than version 0.6.0.
+
+The `squeeze_whitespace` option has been removed since it was
+complicating the above optimization. Let us know if this option is
+important for you so we can provide a work around.
+
+* Fixed [#58][issue-58]: Add a "fast_wrap" function.
+* Fixed [#61][issue-61]: Documentation errors.
+
+### Version 0.6.0 — May 22nd, 2017
+
+Version 0.6.0 adds builder methods to `Wrapper` for easy one-line
+initialization and configuration:
+
+```rust
+let wrapper = Wrapper::new(60).break_words(false);
+```
+
+It also add a new `NoHyphenation` word splitter that will never split
+words, not even at existing hyphens.
+
+* Fixed [#28][issue-28]: Support not squeezing whitespace.
+
+### Version 0.5.0 — May 15th, 2017
+
+Version 0.5.0 has *breaking API changes*. However, this only affects
+code using the hyphenation feature. The feature is now optional, so
+you will first need to enable the `hyphenation` feature as described
+above. Afterwards, please change your code from
+```rust
+wrapper.corpus = Some(&corpus);
+```
+to
+```rust
+wrapper.splitter = Box::new(corpus);
+```
+
+Other changes include optimizations, so version 0.5.0 is roughly
+10-15% faster than version 0.4.0.
+
+* Fixed [#19][issue-19]: Add support for finding terminal size.
+* Fixed [#25][issue-25]: Handle words longer than `self.width`.
+* Fixed [#26][issue-26]: Support custom indentation.
+* Fixed [#36][issue-36]: Support building without `hyphenation`.
+* Fixed [#39][issue-39]: Respect non-breaking spaces.
+
+### Version 0.4.0 — January 24th, 2017
+
+Documented complexities and tested these via `cargo bench`.
+
+* Fixed [#13][issue-13]: Immediatedly add word if it fits.
+* Fixed [#14][issue-14]: Avoid splitting on initial hyphens.
+
+### Version 0.3.0 — January 7th, 2017
+
+Added support for automatic hyphenation.
+
+### Version 0.2.0 — December 28th, 2016
+
+Introduced `Wrapper` struct. Added support for wrapping on hyphens.
+
+### Version 0.1.0 — December 17th, 2016
+
+First public release with support for wrapping strings on whitespace.
+
+## License
+
+Textwrap can be distributed according to the [MIT license][mit].
+Contributions will be accepted under the same license.
+
+[crates-io]: https://crates.io/crates/textwrap
+[travis-ci]: https://travis-ci.org/mgeisler/textwrap
+[appveyor]: https://ci.appveyor.com/project/mgeisler/textwrap
+[codecov]: https://codecov.io/gh/mgeisler/textwrap
+[py-textwrap]: https://docs.python.org/library/textwrap
+[patterns]: https://github.com/tapeinosyne/hyphenation/tree/master/patterns-tex
+[api-docs]: https://docs.rs/textwrap/
+[issue-13]: https://github.com/mgeisler/textwrap/issues/13
+[issue-14]: https://github.com/mgeisler/textwrap/issues/14
+[issue-19]: https://github.com/mgeisler/textwrap/issues/19
+[issue-25]: https://github.com/mgeisler/textwrap/issues/25
+[issue-26]: https://github.com/mgeisler/textwrap/issues/26
+[issue-28]: https://github.com/mgeisler/textwrap/issues/28
+[issue-36]: https://github.com/mgeisler/textwrap/issues/36
+[issue-39]: https://github.com/mgeisler/textwrap/issues/39
+[issue-58]: https://github.com/mgeisler/textwrap/issues/58
+[issue-59]: https://github.com/mgeisler/textwrap/issues/59
+[issue-61]: https://github.com/mgeisler/textwrap/issues/61
+[issue-81]: https://github.com/mgeisler/textwrap/issues/81
+[issue-99]: https://github.com/mgeisler/textwrap/issues/99
+[issue-101]: https://github.com/mgeisler/textwrap/issues/101
+[issue-107]: https://github.com/mgeisler/textwrap/issues/107
+[issue-122]: https://github.com/mgeisler/textwrap/issues/122
+[issue-129]: https://github.com/mgeisler/textwrap/issues/129
+[issue-141]: https://github.com/mgeisler/textwrap/issues/141
+[issue-151]: https://github.com/mgeisler/textwrap/issues/151
+[mit]: LICENSE
diff --git a/textwrap/benches/linear.rs b/textwrap/benches/linear.rs
new file mode 100644
index 0000000..104398a
--- /dev/null
+++ b/textwrap/benches/linear.rs
@@ -0,0 +1,122 @@
+#![feature(test)]
+
+// The benchmarks here verify that the complexity grows as O(*n*)
+// where *n* is the number of characters in the text to be wrapped.
+
+#[cfg(feature = "hyphenation")]
+extern crate hyphenation;
+extern crate lipsum;
+extern crate rand;
+extern crate rand_xorshift;
+extern crate test;
+extern crate textwrap;
+
+#[cfg(feature = "hyphenation")]
+use hyphenation::{Language, Load, Standard};
+use lipsum::MarkovChain;
+use rand::SeedableRng;
+use rand_xorshift::XorShiftRng;
+use test::Bencher;
+#[cfg(feature = "hyphenation")]
+use textwrap::Wrapper;
+
+const LINE_LENGTH: usize = 60;
+
+/// Generate a lorem ipsum text with the given number of characters.
+fn lorem_ipsum(length: usize) -> String {
+ // The average word length in the lorem ipsum text is somewhere
+ // between 6 and 7. So we conservatively divide by 5 to have a
+ // long enough text that we can truncate below.
+ let rng = XorShiftRng::seed_from_u64(0);
+ let mut chain = MarkovChain::new_with_rng(rng);
+ chain.learn(lipsum::LOREM_IPSUM);
+ chain.learn(lipsum::LIBER_PRIMUS);
+
+ let mut text = chain.generate_from(length / 5, ("Lorem", "ipsum"));
+ text.truncate(length);
+ text
+}
+
+#[bench]
+fn fill_100(b: &mut Bencher) {
+ let text = &lorem_ipsum(100);
+ b.iter(|| textwrap::fill(text, LINE_LENGTH))
+}
+
+#[bench]
+fn fill_200(b: &mut Bencher) {
+ let text = &lorem_ipsum(200);
+ b.iter(|| textwrap::fill(text, LINE_LENGTH))
+}
+
+#[bench]
+fn fill_400(b: &mut Bencher) {
+ let text = &lorem_ipsum(400);
+ b.iter(|| textwrap::fill(text, LINE_LENGTH))
+}
+
+#[bench]
+fn fill_800(b: &mut Bencher) {
+ let text = &lorem_ipsum(800);
+ b.iter(|| textwrap::fill(text, LINE_LENGTH))
+}
+
+#[bench]
+fn wrap_100(b: &mut Bencher) {
+ let text = &lorem_ipsum(100);
+ b.iter(|| textwrap::wrap(text, LINE_LENGTH))
+}
+
+#[bench]
+fn wrap_200(b: &mut Bencher) {
+ let text = &lorem_ipsum(200);
+ b.iter(|| textwrap::wrap(text, LINE_LENGTH))
+}
+
+#[bench]
+fn wrap_400(b: &mut Bencher) {
+ let text = &lorem_ipsum(400);
+ b.iter(|| textwrap::wrap(text, LINE_LENGTH))
+}
+
+#[bench]
+fn wrap_800(b: &mut Bencher) {
+ let text = &lorem_ipsum(800);
+ b.iter(|| textwrap::wrap(text, LINE_LENGTH))
+}
+
+#[bench]
+#[cfg(feature = "hyphenation")]
+fn hyphenation_fill_100(b: &mut Bencher) {
+ let text = &lorem_ipsum(100);
+ let dictionary = Standard::from_embedded(Language::Latin).unwrap();
+ let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary);
+ b.iter(|| wrapper.fill(text))
+}
+
+#[bench]
+#[cfg(feature = "hyphenation")]
+fn hyphenation_fill_200(b: &mut Bencher) {
+ let text = &lorem_ipsum(200);
+ let dictionary = Standard::from_embedded(Language::Latin).unwrap();
+ let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary);
+ b.iter(|| wrapper.fill(text))
+}
+
+#[bench]
+#[cfg(feature = "hyphenation")]
+fn hyphenation_fill_400(b: &mut Bencher) {
+ let text = &lorem_ipsum(400);
+ let dictionary = Standard::from_embedded(Language::Latin).unwrap();
+ let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary);
+ b.iter(|| wrapper.fill(text))
+}
+
+#[bench]
+#[cfg(feature = "hyphenation")]
+fn hyphenation_fill_800(b: &mut Bencher) {
+ let text = &lorem_ipsum(800);
+ let dictionary = Standard::from_embedded(Language::Latin).unwrap();
+ let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary);
+ b.iter(|| wrapper.fill(text))
+}
diff --git a/textwrap/examples/layout.rs b/textwrap/examples/layout.rs
new file mode 100644
index 0000000..d36cb3a
--- /dev/null
+++ b/textwrap/examples/layout.rs
@@ -0,0 +1,38 @@
+#[cfg(feature = "hyphenation")]
+extern crate hyphenation;
+extern crate textwrap;
+
+#[cfg(feature = "hyphenation")]
+use hyphenation::{Language, Load};
+use textwrap::Wrapper;
+
+#[cfg(not(feature = "hyphenation"))]
+fn new_wrapper<'a>() -> Wrapper<'a, textwrap::HyphenSplitter> {
+ Wrapper::new(0)
+}
+
+#[cfg(feature = "hyphenation")]
+fn new_wrapper<'a>() -> Wrapper<'a, hyphenation::Standard> {
+ let dictionary = hyphenation::Standard::from_embedded(Language::EnglishUS).unwrap();
+ Wrapper::with_splitter(0, dictionary)
+}
+
+fn main() {
+ let example = "Memory safety without garbage collection. \
+ Concurrency without data races. \
+ Zero-cost abstractions.";
+ let mut prev_lines = vec![];
+ let mut wrapper = new_wrapper();
+ for width in 15..60 {
+ wrapper.width = width;
+ let lines = wrapper.wrap(example);
+ if lines != prev_lines {
+ let title = format!(" Width: {} ", width);
+ println!(".{:-^1$}.", title, width + 2);
+ for line in &lines {
+ println!("| {:1$} |", line, width);
+ }
+ prev_lines = lines;
+ }
+ }
+}
diff --git a/textwrap/examples/termwidth.rs b/textwrap/examples/termwidth.rs
new file mode 100644
index 0000000..75db3aa
--- /dev/null
+++ b/textwrap/examples/termwidth.rs
@@ -0,0 +1,41 @@
+#[cfg(feature = "hyphenation")]
+extern crate hyphenation;
+extern crate textwrap;
+
+#[cfg(feature = "hyphenation")]
+use hyphenation::{Language, Load, Standard};
+#[cfg(feature = "term_size")]
+use textwrap::Wrapper;
+
+#[cfg(not(feature = "term_size"))]
+fn main() {
+ println!("Please enable the term_size feature to run this example.");
+}
+
+#[cfg(feature = "term_size")]
+fn main() {
+ #[cfg(not(feature = "hyphenation"))]
+ fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, textwrap::HyphenSplitter>) {
+ ("without hyphenation", Wrapper::with_termwidth())
+ }
+
+ #[cfg(feature = "hyphenation")]
+ fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, Standard>) {
+ let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
+ (
+ "with hyphenation",
+ Wrapper::with_splitter(textwrap::termwidth(), dictionary),
+ )
+ }
+
+ let example = "Memory safety without garbage collection. \
+ Concurrency without data races. \
+ Zero-cost abstractions.";
+ // Create a new Wrapper -- automatically set the width to the
+ // current terminal width.
+ let (msg, wrapper) = new_wrapper();
+ println!("Formatted {} in {} columns:", msg, wrapper.width);
+ println!("----");
+ println!("{}", wrapper.fill(example));
+ println!("----");
+}
diff --git a/textwrap/src/indentation.rs b/textwrap/src/indentation.rs
new file mode 100644
index 0000000..276ba10
--- /dev/null
+++ b/textwrap/src/indentation.rs
@@ -0,0 +1,294 @@
+//! Functions related to adding and removing indentation from lines of
+//! text.
+//!
+//! The functions here can be used to uniformly indent or dedent
+//! (unindent) word wrapped lines of text.
+
+/// Add prefix to each non-empty line.
+///
+/// ```
+/// use textwrap::indent;
+///
+/// assert_eq!(indent("
+/// Foo
+/// Bar
+/// ", " "), "
+/// Foo
+/// Bar
+/// ");
+/// ```
+///
+/// Empty lines (lines consisting only of whitespace) are not indented
+/// and the whitespace is replaced by a single newline (`\n`):
+///
+/// ```
+/// use textwrap::indent;
+///
+/// assert_eq!(indent("
+/// Foo
+///
+/// Bar
+/// \t
+/// Baz
+/// ", "->"), "
+/// ->Foo
+///
+/// ->Bar
+///
+/// ->Baz
+/// ");
+/// ```
+///
+/// Leading and trailing whitespace on non-empty lines is kept
+/// unchanged:
+///
+/// ```
+/// use textwrap::indent;
+///
+/// assert_eq!(indent(" \t Foo ", "->"), "-> \t Foo \n");
+/// ```
+pub fn indent(s: &str, prefix: &str) -> String {
+ let mut result = String::new();
+ for line in s.lines() {
+ if line.chars().any(|c| !c.is_whitespace()) {
+ result.push_str(prefix);
+ result.push_str(line);
+ }
+ result.push('\n');
+ }
+ result
+}
+
+/// Removes common leading whitespace from each line.
+///
+/// This function will look at each non-empty line and determine the
+/// maximum amount of whitespace that can be removed from all lines:
+///
+/// ```
+/// use textwrap::dedent;
+///
+/// assert_eq!(dedent("
+/// 1st line
+/// 2nd line
+/// 3rd line
+/// "), "
+/// 1st line
+/// 2nd line
+/// 3rd line
+/// ");
+/// ```
+pub fn dedent(s: &str) -> String {
+ let mut prefix = "";
+ let mut lines = s.lines();
+
+ // We first search for a non-empty line to find a prefix.
+ for line in &mut lines {
+ let mut whitespace_idx = line.len();
+ for (idx, ch) in line.char_indices() {
+ if !ch.is_whitespace() {
+ whitespace_idx = idx;
+ break;
+ }
+ }
+
+ // Check if the line had anything but whitespace
+ if whitespace_idx < line.len() {
+ prefix = &line[..whitespace_idx];
+ break;
+ }
+ }
+
+ // We then continue looking through the remaining lines to
+ // possibly shorten the prefix.
+ for line in &mut lines {
+ let mut whitespace_idx = line.len();
+ for ((idx, a), b) in line.char_indices().zip(prefix.chars()) {
+ if a != b {
+ whitespace_idx = idx;
+ break;
+ }
+ }
+
+ // Check if the line had anything but whitespace and if we
+ // have found a shorter prefix
+ if whitespace_idx < line.len() && whitespace_idx < prefix.len() {
+ prefix = &line[..whitespace_idx];
+ }
+ }
+
+ // We now go over the lines a second time to build the result.
+ let mut result = String::new();
+ for line in s.lines() {
+ if line.starts_with(&prefix) && line.chars().any(|c| !c.is_whitespace()) {
+ let (_, tail) = line.split_at(prefix.len());
+ result.push_str(tail);
+ }
+ result.push('\n');
+ }
+
+ if result.ends_with('\n') && !s.ends_with('\n') {
+ let new_len = result.len() - 1;
+ result.truncate(new_len);
+ }
+
+ result
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ /// Add newlines. Ensures that the final line in the vector also
+ /// has a newline.
+ fn add_nl(lines: &[&str]) -> String {
+ lines.join("\n") + "\n"
+ }
+
+ #[test]
+ fn indent_empty() {
+ assert_eq!(indent("\n", " "), "\n");
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn indent_nonempty() {
+ let x = vec![" foo",
+ "bar",
+ " baz"];
+ let y = vec!["// foo",
+ "//bar",
+ "// baz"];
+ assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn indent_empty_line() {
+ let x = vec![" foo",
+ "bar",
+ "",
+ " baz"];
+ let y = vec!["// foo",
+ "//bar",
+ "",
+ "// baz"];
+ assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));
+ }
+
+ #[test]
+ fn dedent_empty() {
+ assert_eq!(dedent(""), "");
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_multi_line() {
+ let x = vec![" foo",
+ " bar",
+ " baz"];
+ let y = vec![" foo",
+ "bar",
+ " baz"];
+ assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_empty_line() {
+ let x = vec![" foo",
+ " bar",
+ " ",
+ " baz"];
+ let y = vec![" foo",
+ "bar",
+ "",
+ " baz"];
+ assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_blank_line() {
+ let x = vec![" foo",
+ "",
+ " bar",
+ " foo",
+ " bar",
+ " baz"];
+ let y = vec!["foo",
+ "",
+ " bar",
+ " foo",
+ " bar",
+ " baz"];
+ assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_whitespace_line() {
+ let x = vec![" foo",
+ " ",
+ " bar",
+ " foo",
+ " bar",
+ " baz"];
+ let y = vec!["foo",
+ "",
+ " bar",
+ " foo",
+ " bar",
+ " baz"];
+ assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_mixed_whitespace() {
+ let x = vec!["\tfoo",
+ " bar"];
+ let y = vec!["\tfoo",
+ " bar"];
+ assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_tabbed_whitespace() {
+ let x = vec!["\t\tfoo",
+ "\t\t\tbar"];
+ let y = vec!["foo",
+ "\tbar"];
+ assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_mixed_tabbed_whitespace() {
+ let x = vec!["\t \tfoo",
+ "\t \t\tbar"];
+ let y = vec!["foo",
+ "\tbar"];
+ assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_mixed_tabbed_whitespace2() {
+ let x = vec!["\t \tfoo",
+ "\t \tbar"];
+ let y = vec!["\tfoo",
+ " \tbar"];
+ assert_eq!(dedent(&add_nl(&x)), add_nl(&y));
+ }
+
+ #[test]
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ fn dedent_preserve_no_terminating_newline() {
+ let x = vec![" foo",
+ " bar"].join("\n");
+ let y = vec!["foo",
+ " bar"].join("\n");
+ assert_eq!(dedent(&x), y);
+ }
+}
diff --git a/textwrap/src/lib.rs b/textwrap/src/lib.rs
new file mode 100644
index 0000000..2f82325
--- /dev/null
+++ b/textwrap/src/lib.rs
@@ -0,0 +1,987 @@
+//! `textwrap` provides functions for word wrapping and filling text.
+//!
+//! Wrapping text can be very useful in commandline programs where you
+//! want to format dynamic output nicely so it looks good in a
+//! terminal. A quick example:
+//!
+//! ```no_run
+//! extern crate textwrap;
+//! use textwrap::fill;
+//!
+//! fn main() {
+//! let text = "textwrap: a small library for wrapping text.";
+//! println!("{}", fill(text, 18));
+//! }
+//! ```
+//!
+//! This will display the following output:
+//!
+//! ```text
+//! textwrap: a small
+//! library for
+//! wrapping text.
+//! ```
+//!
+//! # Displayed Width vs Byte Size
+//!
+//! To word wrap text, one must know the width of each word so one can
+//! know when to break lines. This library measures the width of text
+//! using the [displayed width][unicode-width], not the size in bytes.
+//!
+//! This is important for non-ASCII text. ASCII characters such as `a`
+//! and `!` are simple and take up one column each. This means that
+//! the displayed width is equal to the string length in bytes.
+//! However, non-ASCII characters and symbols take up more than one
+//! byte when UTF-8 encoded: `é` is `0xc3 0xa9` (two bytes) and `⚙` is
+//! `0xe2 0x9a 0x99` (three bytes) in UTF-8, respectively.
+//!
+//! This is why we take care to use the displayed width instead of the
+//! byte count when computing line lengths. All functions in this
+//! library handle Unicode characters like this.
+//!
+//! [unicode-width]: https://docs.rs/unicode-width/
+
+#![doc(html_root_url = "https://docs.rs/textwrap/0.11.0")]
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+
+#[cfg(feature = "hyphenation")]
+extern crate hyphenation;
+#[cfg(feature = "term_size")]
+extern crate term_size;
+extern crate unicode_width;
+
+use std::borrow::Cow;
+use std::str::CharIndices;
+
+use unicode_width::UnicodeWidthChar;
+use unicode_width::UnicodeWidthStr;
+
+/// A non-breaking space.
+const NBSP: char = '\u{a0}';
+
+mod indentation;
+pub use indentation::dedent;
+pub use indentation::indent;
+
+mod splitting;
+pub use splitting::{HyphenSplitter, NoHyphenation, WordSplitter};
+
+/// A Wrapper holds settings for wrapping and filling text. Use it
+/// when the convenience [`wrap_iter`], [`wrap`] and [`fill`] functions
+/// are not flexible enough.
+///
+/// [`wrap_iter`]: fn.wrap_iter.html
+/// [`wrap`]: fn.wrap.html
+/// [`fill`]: fn.fill.html
+///
+/// The algorithm used by the `WrapIter` iterator (returned from the
+/// `wrap_iter` method) works by doing successive partial scans over
+/// words in the input string (where each single scan yields a single
+/// line) so that the overall time and memory complexity is O(*n*) where
+/// *n* is the length of the input string.
+#[derive(Clone, Debug)]
+pub struct Wrapper<'a, S: WordSplitter> {
+ /// The width in columns at which the text will be wrapped.
+ pub width: usize,
+ /// Indentation used for the first line of output.
+ pub initial_indent: &'a str,
+ /// Indentation used for subsequent lines of output.
+ pub subsequent_indent: &'a str,
+ /// Allow long words to be broken if they cannot fit on a line.
+ /// When set to `false`, some lines may be longer than
+ /// `self.width`.
+ pub break_words: bool,
+ /// The method for splitting words. If the `hyphenation` feature
+ /// is enabled, you can use a `hyphenation::Standard` dictionary
+ /// here to get language-aware hyphenation.
+ pub splitter: S,
+}
+
+impl<'a> Wrapper<'a, HyphenSplitter> {
+ /// Create a new Wrapper for wrapping at the specified width. By
+ /// default, we allow words longer than `width` to be broken. A
+ /// [`HyphenSplitter`] will be used by default for splitting
+ /// words. See the [`WordSplitter`] trait for other options.
+ ///
+ /// [`HyphenSplitter`]: struct.HyphenSplitter.html
+ /// [`WordSplitter`]: trait.WordSplitter.html
+ pub fn new(width: usize) -> Wrapper<'a, HyphenSplitter> {
+ Wrapper::with_splitter(width, HyphenSplitter)
+ }
+
+ /// Create a new Wrapper for wrapping text at the current terminal
+ /// width. If the terminal width cannot be determined (typically
+ /// because the standard input and output is not connected to a
+ /// terminal), a width of 80 characters will be used. Other
+ /// settings use the same defaults as `Wrapper::new`.
+ ///
+ /// Equivalent to:
+ ///
+ /// ```no_run
+ /// # #![allow(unused_variables)]
+ /// use textwrap::{Wrapper, termwidth};
+ ///
+ /// let wrapper = Wrapper::new(termwidth());
+ /// ```
+ #[cfg(feature = "term_size")]
+ pub fn with_termwidth() -> Wrapper<'a, HyphenSplitter> {
+ Wrapper::new(termwidth())
+ }
+}
+
+impl<'a, S: WordSplitter> Wrapper<'a, S> {
+ /// Use the given [`WordSplitter`] to create a new Wrapper for
+ /// wrapping at the specified width. By default, we allow words
+ /// longer than `width` to be broken.
+ ///
+ /// [`WordSplitter`]: trait.WordSplitter.html
+ pub fn with_splitter(width: usize, splitter: S) -> Wrapper<'a, S> {
+ Wrapper {
+ width: width,
+ initial_indent: "",
+ subsequent_indent: "",
+ break_words: true,
+ splitter: splitter,
+ }
+ }
+
+ /// Change [`self.initial_indent`]. The initial indentation is
+ /// used on the very first line of output.
+ ///
+ /// # Examples
+ ///
+ /// Classic paragraph indentation can be achieved by specifying an
+ /// initial indentation and wrapping each paragraph by itself:
+ ///
+ /// ```no_run
+ /// # #![allow(unused_variables)]
+ /// use textwrap::Wrapper;
+ ///
+ /// let wrapper = Wrapper::new(15).initial_indent(" ");
+ /// ```
+ ///
+ /// [`self.initial_indent`]: #structfield.initial_indent
+ pub fn initial_indent(self, indent: &'a str) -> Wrapper<'a, S> {
+ Wrapper {
+ initial_indent: indent,
+ ..self
+ }
+ }
+
+ /// Change [`self.subsequent_indent`]. The subsequent indentation
+ /// is used on lines following the first line of output.
+ ///
+ /// # Examples
+ ///
+ /// Combining initial and subsequent indentation lets you format a
+ /// single paragraph as a bullet list:
+ ///
+ /// ```no_run
+ /// # #![allow(unused_variables)]
+ /// use textwrap::Wrapper;
+ ///
+ /// let wrapper = Wrapper::new(15)
+ /// .initial_indent("* ")
+ /// .subsequent_indent(" ");
+ /// ```
+ ///
+ /// [`self.subsequent_indent`]: #structfield.subsequent_indent
+ pub fn subsequent_indent(self, indent: &'a str) -> Wrapper<'a, S> {
+ Wrapper {
+ subsequent_indent: indent,
+ ..self
+ }
+ }
+
+ /// Change [`self.break_words`]. This controls if words longer
+ /// than `self.width` can be broken, or if they will be left
+ /// sticking out into the right margin.
+ ///
+ /// [`self.break_words`]: #structfield.break_words
+ pub fn break_words(self, setting: bool) -> Wrapper<'a, S> {
+ Wrapper {
+ break_words: setting,
+ ..self
+ }
+ }
+
+ /// Fill a line of text at `self.width` characters. Strings are
+ /// wrapped based on their displayed width, not their size in
+ /// bytes.
+ ///
+ /// The result is a string with newlines between each line. Use
+ /// the `wrap` method if you need access to the individual lines.
+ ///
+ /// # Complexities
+ ///
+ /// This method simply joins the lines produced by `wrap_iter`. As
+ /// such, it inherits the O(*n*) time and memory complexity where
+ /// *n* is the input string length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use textwrap::Wrapper;
+ ///
+ /// let wrapper = Wrapper::new(15);
+ /// assert_eq!(wrapper.fill("Memory safety without garbage collection."),
+ /// "Memory safety\nwithout garbage\ncollection.");
+ /// ```
+ pub fn fill(&self, s: &str) -> String {
+ // This will avoid reallocation in simple cases (no
+ // indentation, no hyphenation).
+ let mut result = String::with_capacity(s.len());
+
+ for (i, line) in self.wrap_iter(s).enumerate() {
+ if i > 0 {
+ result.push('\n');
+ }
+ result.push_str(&line);
+ }
+
+ result
+ }
+
+ /// Wrap a line of text at `self.width` characters. Strings are
+ /// wrapped based on their displayed width, not their size in
+ /// bytes.
+ ///
+ /// # Complexities
+ ///
+ /// This method simply collects the lines produced by `wrap_iter`.
+ /// As such, it inherits the O(*n*) overall time and memory
+ /// complexity where *n* is the input string length.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use textwrap::Wrapper;
+ ///
+ /// let wrap15 = Wrapper::new(15);
+ /// assert_eq!(wrap15.wrap("Concurrency without data races."),
+ /// vec!["Concurrency",
+ /// "without data",
+ /// "races."]);
+ ///
+ /// let wrap20 = Wrapper::new(20);
+ /// assert_eq!(wrap20.wrap("Concurrency without data races."),
+ /// vec!["Concurrency without",
+ /// "data races."]);
+ /// ```
+ ///
+ /// Notice that newlines in the input are preserved. This means
+ /// that they force a line break, regardless of how long the
+ /// current line is:
+ ///
+ /// ```
+ /// use textwrap::Wrapper;
+ ///
+ /// let wrapper = Wrapper::new(40);
+ /// assert_eq!(wrapper.wrap("First line.\nSecond line."),
+ /// vec!["First line.", "Second line."]);
+ /// ```
+ ///
+ pub fn wrap(&self, s: &'a str) -> Vec<Cow<'a, str>> {
+ self.wrap_iter(s).collect::<Vec<_>>()
+ }
+
+ /// Lazily wrap a line of text at `self.width` characters. Strings
+ /// are wrapped based on their displayed width, not their size in
+ /// bytes.
+ ///
+ /// The [`WordSplitter`] stored in [`self.splitter`] is used
+ /// whenever when a word is too large to fit on the current line.
+ /// By changing the field, different hyphenation strategies can be
+ /// implemented.
+ ///
+ /// # Complexities
+ ///
+ /// This method returns a [`WrapIter`] iterator which borrows this
+ /// `Wrapper`. The algorithm used has a linear complexity, so
+ /// getting the next line from the iterator will take O(*w*) time,
+ /// where *w* is the wrapping width. Fully processing the iterator
+ /// will take O(*n*) time for an input string of length *n*.
+ ///
+ /// When no indentation is used, each line returned is a slice of
+ /// the input string and the memory overhead is thus constant.
+ /// Otherwise new memory is allocated for each line returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ /// use textwrap::Wrapper;
+ ///
+ /// let wrap20 = Wrapper::new(20);
+ /// let mut wrap20_iter = wrap20.wrap_iter("Zero-cost abstractions.");
+ /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost")));
+ /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions.")));
+ /// assert_eq!(wrap20_iter.next(), None);
+ ///
+ /// let wrap25 = Wrapper::new(25);
+ /// let mut wrap25_iter = wrap25.wrap_iter("Zero-cost abstractions.");
+ /// assert_eq!(wrap25_iter.next(), Some(Cow::from("Zero-cost abstractions.")));
+ /// assert_eq!(wrap25_iter.next(), None);
+ /// ```
+ ///
+ /// [`self.splitter`]: #structfield.splitter
+ /// [`WordSplitter`]: trait.WordSplitter.html
+ /// [`WrapIter`]: struct.WrapIter.html
+ pub fn wrap_iter<'w>(&'w self, s: &'a str) -> WrapIter<'w, 'a, S> {
+ WrapIter {
+ wrapper: self,
+ inner: WrapIterImpl::new(self, s),
+ }
+ }
+
+ /// Lazily wrap a line of text at `self.width` characters. Strings
+ /// are wrapped based on their displayed width, not their size in
+ /// bytes.
+ ///
+ /// The [`WordSplitter`] stored in [`self.splitter`] is used
+ /// whenever when a word is too large to fit on the current line.
+ /// By changing the field, different hyphenation strategies can be
+ /// implemented.
+ ///
+ /// # Complexities
+ ///
+ /// This method consumes the `Wrapper` and returns a
+ /// [`IntoWrapIter`] iterator. Fully processing the iterator has
+ /// the same O(*n*) time complexity as [`wrap_iter`], where *n* is
+ /// the length of the input string.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::borrow::Cow;
+ /// use textwrap::Wrapper;
+ ///
+ /// let wrap20 = Wrapper::new(20);
+ /// let mut wrap20_iter = wrap20.into_wrap_iter("Zero-cost abstractions.");
+ /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost")));
+ /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions.")));
+ /// assert_eq!(wrap20_iter.next(), None);
+ /// ```
+ ///
+ /// [`self.splitter`]: #structfield.splitter
+ /// [`WordSplitter`]: trait.WordSplitter.html
+ /// [`IntoWrapIter`]: struct.IntoWrapIter.html
+ /// [`wrap_iter`]: #method.wrap_iter
+ pub fn into_wrap_iter(self, s: &'a str) -> IntoWrapIter<'a, S> {
+ let inner = WrapIterImpl::new(&self, s);
+
+ IntoWrapIter {
+ wrapper: self,
+ inner: inner,
+ }
+ }
+}
+
+/// An iterator over the lines of the input string which owns a
+/// `Wrapper`. An instance of `IntoWrapIter` is typically obtained
+/// through either [`wrap_iter`] or [`Wrapper::into_wrap_iter`].
+///
+/// Each call of `.next()` method yields a line wrapped in `Some` if the
+/// input hasn't been fully processed yet. Otherwise it returns `None`.
+///
+/// [`wrap_iter`]: fn.wrap_iter.html
+/// [`Wrapper::into_wrap_iter`]: struct.Wrapper.html#method.into_wrap_iter
+#[derive(Debug)]
+pub struct IntoWrapIter<'a, S: WordSplitter> {
+ wrapper: Wrapper<'a, S>,
+ inner: WrapIterImpl<'a>,
+}
+
+impl<'a, S: WordSplitter> Iterator for IntoWrapIter<'a, S> {
+ type Item = Cow<'a, str>;
+
+ fn next(&mut self) -> Option<Cow<'a, str>> {
+ self.inner.next(&self.wrapper)
+ }
+}
+
+/// An iterator over the lines of the input string which borrows a
+/// `Wrapper`. An instance of `WrapIter` is typically obtained
+/// through the [`Wrapper::wrap_iter`] method.
+///
+/// Each call of `.next()` method yields a line wrapped in `Some` if the
+/// input hasn't been fully processed yet. Otherwise it returns `None`.
+///
+/// [`Wrapper::wrap_iter`]: struct.Wrapper.html#method.wrap_iter
+#[derive(Debug)]
+pub struct WrapIter<'w, 'a: 'w, S: WordSplitter + 'w> {
+ wrapper: &'w Wrapper<'a, S>,
+ inner: WrapIterImpl<'a>,
+}
+
+impl<'w, 'a: 'w, S: WordSplitter> Iterator for WrapIter<'w, 'a, S> {
+ type Item = Cow<'a, str>;
+
+ fn next(&mut self) -> Option<Cow<'a, str>> {
+ self.inner.next(self.wrapper)
+ }
+}
+
+/// Like `char::is_whitespace`, but non-breaking spaces don't count.
+#[inline]
+fn is_whitespace(ch: char) -> bool {
+ ch.is_whitespace() && ch != NBSP
+}
+
+/// Common implementation details for `WrapIter` and `IntoWrapIter`.
+#[derive(Debug)]
+struct WrapIterImpl<'a> {
+ // String to wrap.
+ source: &'a str,
+ // CharIndices iterator over self.source.
+ char_indices: CharIndices<'a>,
+ // Byte index where the current line starts.
+ start: usize,
+ // Byte index of the last place where the string can be split.
+ split: usize,
+ // Size in bytes of the character at self.source[self.split].
+ split_len: usize,
+ // Width of self.source[self.start..idx].
+ line_width: usize,
+ // Width of self.source[self.start..self.split].
+ line_width_at_split: usize,
+ // Tracking runs of whitespace characters.
+ in_whitespace: bool,
+ // Has iterator finished producing elements?
+ finished: bool,
+}
+
+impl<'a> WrapIterImpl<'a> {
+ fn new<S: WordSplitter>(wrapper: &Wrapper<'a, S>, s: &'a str) -> WrapIterImpl<'a> {
+ WrapIterImpl {
+ source: s,
+ char_indices: s.char_indices(),
+ start: 0,
+ split: 0,
+ split_len: 0,
+ line_width: wrapper.initial_indent.width(),
+ line_width_at_split: wrapper.initial_indent.width(),
+ in_whitespace: false,
+ finished: false,
+ }
+ }
+
+ fn create_result_line<S: WordSplitter>(&self, wrapper: &Wrapper<'a, S>) -> Cow<'a, str> {
+ if self.start == 0 {
+ Cow::from(wrapper.initial_indent)
+ } else {
+ Cow::from(wrapper.subsequent_indent)
+ }
+ }
+
+ fn next<S: WordSplitter>(&mut self, wrapper: &Wrapper<'a, S>) -> Option<Cow<'a, str>> {
+ if self.finished {
+ return None;
+ }
+
+ while let Some((idx, ch)) = self.char_indices.next() {
+ let char_width = ch.width().unwrap_or(0);
+ let char_len = ch.len_utf8();
+
+ if ch == '\n' {
+ self.split = idx;
+ self.split_len = char_len;
+ self.line_width_at_split = self.line_width;
+ self.in_whitespace = false;
+
+ // If this is not the final line, return the current line. Otherwise,
+ // we will return the line with its line break after exiting the loop
+ if self.split + self.split_len < self.source.len() {
+ let mut line = self.create_result_line(wrapper);
+ line += &self.source[self.start..self.split];
+
+ self.start = self.split + self.split_len;
+ self.line_width = wrapper.subsequent_indent.width();
+
+ return Some(line);
+ }
+ } else if is_whitespace(ch) {
+ // Extend the previous split or create a new one.
+ if self.in_whitespace {
+ self.split_len += char_len;
+ } else {
+ self.split = idx;
+ self.split_len = char_len;
+ }
+ self.line_width_at_split = self.line_width + char_width;
+ self.in_whitespace = true;
+ } else if self.line_width + char_width > wrapper.width {
+ // There is no room for this character on the current
+ // line. Try to split the final word.
+ self.in_whitespace = false;
+ let remaining_text = &self.source[self.split + self.split_len..];
+ let final_word = match remaining_text.find(is_whitespace) {
+ Some(i) => &remaining_text[..i],
+ None => remaining_text,
+ };
+
+ let mut hyphen = "";
+ let splits = wrapper.splitter.split(final_word);
+ for &(head, hyp, _) in splits.iter().rev() {
+ if self.line_width_at_split + head.width() + hyp.width() <= wrapper.width {
+ // We can fit head into the current line.
+ // Advance the split point by the width of the
+ // whitespace and the head length.
+ self.split += self.split_len + head.len();
+ self.split_len = 0;
+ hyphen = hyp;
+ break;
+ }
+ }
+
+ if self.start >= self.split {
+ // The word is too big to fit on a single line, so we
+ // need to split it at the current index.
+ if wrapper.break_words {
+ // Break work at current index.
+ self.split = idx;
+ self.split_len = 0;
+ self.line_width_at_split = self.line_width;
+ } else {
+ // Add smallest split.
+ self.split = self.start + splits[0].0.len();
+ self.split_len = 0;
+ self.line_width_at_split = self.line_width;
+ }
+ }
+
+ if self.start < self.split {
+ let mut line = self.create_result_line(wrapper);
+ line += &self.source[self.start..self.split];
+ line += hyphen;
+
+ self.start = self.split + self.split_len;
+ self.line_width += wrapper.subsequent_indent.width();
+ self.line_width -= self.line_width_at_split;
+ self.line_width += char_width;
+
+ return Some(line);
+ }
+ } else {
+ self.in_whitespace = false;
+ }
+ self.line_width += char_width;
+ }
+
+ self.finished = true;
+
+ // Add final line.
+ if self.start < self.source.len() {
+ let mut line = self.create_result_line(wrapper);
+ line += &self.source[self.start..];
+ return Some(line);
+ }
+
+ None
+ }
+}
+
+/// Return the current terminal width. If the terminal width cannot be
+/// determined (typically because the standard output is not connected
+/// to a terminal), a default width of 80 characters will be used.
+///
+/// # Examples
+///
+/// Create a `Wrapper` for the current terminal with a two column
+/// margin:
+///
+/// ```no_run
+/// # #![allow(unused_variables)]
+/// use textwrap::{Wrapper, NoHyphenation, termwidth};
+///
+/// let width = termwidth() - 4; // Two columns on each side.
+/// let wrapper = Wrapper::with_splitter(width, NoHyphenation)
+/// .initial_indent(" ")
+/// .subsequent_indent(" ");
+/// ```
+#[cfg(feature = "term_size")]
+pub fn termwidth() -> usize {
+ term_size::dimensions_stdout().map_or(80, |(w, _)| w)
+}
+
+/// Fill a line of text at `width` characters. Strings are wrapped
+/// based on their displayed width, not their size in bytes.
+///
+/// The result is a string with newlines between each line. Use
+/// [`wrap`] if you need access to the individual lines or
+/// [`wrap_iter`] for its iterator counterpart.
+///
+/// ```
+/// use textwrap::fill;
+///
+/// assert_eq!(fill("Memory safety without garbage collection.", 15),
+/// "Memory safety\nwithout garbage\ncollection.");
+/// ```
+///
+/// This function creates a Wrapper on the fly with default settings.
+/// If you need to set a language corpus for automatic hyphenation, or
+/// need to fill many strings, then it is suggested to create a Wrapper
+/// and call its [`fill` method].
+///
+/// [`wrap`]: fn.wrap.html
+/// [`wrap_iter`]: fn.wrap_iter.html
+/// [`fill` method]: struct.Wrapper.html#method.fill
+pub fn fill(s: &str, width: usize) -> String {
+ Wrapper::new(width).fill(s)
+}
+
+/// Wrap a line of text at `width` characters. Strings are wrapped
+/// based on their displayed width, not their size in bytes.
+///
+/// This function creates a Wrapper on the fly with default settings.
+/// If you need to set a language corpus for automatic hyphenation, or
+/// need to wrap many strings, then it is suggested to create a Wrapper
+/// and call its [`wrap` method].
+///
+/// The result is a vector of strings. Use [`wrap_iter`] if you need an
+/// iterator version.
+///
+/// # Examples
+///
+/// ```
+/// use textwrap::wrap;
+///
+/// assert_eq!(wrap("Concurrency without data races.", 15),
+/// vec!["Concurrency",
+/// "without data",
+/// "races."]);
+///
+/// assert_eq!(wrap("Concurrency without data races.", 20),
+/// vec!["Concurrency without",
+/// "data races."]);
+/// ```
+///
+/// [`wrap_iter`]: fn.wrap_iter.html
+/// [`wrap` method]: struct.Wrapper.html#method.wrap
+pub fn wrap(s: &str, width: usize) -> Vec<Cow<str>> {
+ Wrapper::new(width).wrap(s)
+}
+
+/// Lazily wrap a line of text at `width` characters. Strings are
+/// wrapped based on their displayed width, not their size in bytes.
+///
+/// This function creates a Wrapper on the fly with default settings.
+/// It then calls the [`into_wrap_iter`] method. Hence, the return
+/// value is an [`IntoWrapIter`], not a [`WrapIter`] as the function
+/// name would otherwise suggest.
+///
+/// If you need to set a language corpus for automatic hyphenation, or
+/// need to wrap many strings, then it is suggested to create a Wrapper
+/// and call its [`wrap_iter`] or [`into_wrap_iter`] methods.
+///
+/// # Examples
+///
+/// ```
+/// use std::borrow::Cow;
+/// use textwrap::wrap_iter;
+///
+/// let mut wrap20_iter = wrap_iter("Zero-cost abstractions.", 20);
+/// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost")));
+/// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions.")));
+/// assert_eq!(wrap20_iter.next(), None);
+///
+/// let mut wrap25_iter = wrap_iter("Zero-cost abstractions.", 25);
+/// assert_eq!(wrap25_iter.next(), Some(Cow::from("Zero-cost abstractions.")));
+/// assert_eq!(wrap25_iter.next(), None);
+/// ```
+///
+/// [`wrap_iter`]: struct.Wrapper.html#method.wrap_iter
+/// [`into_wrap_iter`]: struct.Wrapper.html#method.into_wrap_iter
+/// [`IntoWrapIter`]: struct.IntoWrapIter.html
+/// [`WrapIter`]: struct.WrapIter.html
+pub fn wrap_iter(s: &str, width: usize) -> IntoWrapIter<HyphenSplitter> {
+ Wrapper::new(width).into_wrap_iter(s)
+}
+
+#[cfg(test)]
+mod tests {
+ #[cfg(feature = "hyphenation")]
+ extern crate hyphenation;
+
+ use super::*;
+ #[cfg(feature = "hyphenation")]
+ use hyphenation::{Language, Load, Standard};
+
+ #[test]
+ fn no_wrap() {
+ assert_eq!(wrap("foo", 10), vec!["foo"]);
+ }
+
+ #[test]
+ fn simple() {
+ assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
+ }
+
+ #[test]
+ fn multi_word_on_line() {
+ assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
+ }
+
+ #[test]
+ fn long_word() {
+ assert_eq!(wrap("foo", 0), vec!["f", "o", "o"]);
+ }
+
+ #[test]
+ fn long_words() {
+ assert_eq!(wrap("foo bar", 0), vec!["f", "o", "o", "b", "a", "r"]);
+ }
+
+ #[test]
+ fn max_width() {
+ assert_eq!(wrap("foo bar", usize::max_value()), vec!["foo bar"]);
+ }
+
+ #[test]
+ fn leading_whitespace() {
+ assert_eq!(wrap(" foo bar", 6), vec![" foo", "bar"]);
+ }
+
+ #[test]
+ fn trailing_whitespace() {
+ assert_eq!(wrap("foo bar ", 6), vec!["foo", "bar "]);
+ }
+
+ #[test]
+ fn interior_whitespace() {
+ assert_eq!(wrap("foo: bar baz", 10), vec!["foo: bar", "baz"]);
+ }
+
+ #[test]
+ fn extra_whitespace_start_of_line() {
+ // Whitespace is only significant inside a line. After a line
+ // gets too long and is broken, the first word starts in
+ // column zero and is not indented. The line before might end
+ // up with trailing whitespace.
+ assert_eq!(wrap("foo bar", 5), vec!["foo", "bar"]);
+ }
+
+ #[test]
+ fn issue_99() {
+ // We did not reset the in_whitespace flag correctly and did
+ // not handle single-character words after a line break.
+ assert_eq!(
+ wrap("aaabbbccc x yyyzzzwww", 9),
+ vec!["aaabbbccc", "x", "yyyzzzwww"]
+ );
+ }
+
+ #[test]
+ fn issue_129() {
+ // The dash is an em-dash which takes up four bytes. We used
+ // to panic since we tried to index into the character.
+ assert_eq!(wrap("x – x", 1), vec!["x", "–", "x"]);
+ }
+
+ #[test]
+ fn wide_character_handling() {
+ assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]);
+ assert_eq!(
+ wrap("Hello, World!", 15),
+ vec!["Hello,", "World!"]
+ );
+ }
+
+ #[test]
+ fn empty_input_not_indented() {
+ let wrapper = Wrapper::new(10).initial_indent("!!!");
+ assert_eq!(wrapper.fill(""), "");
+ }
+
+ #[test]
+ fn indent_single_line() {
+ let wrapper = Wrapper::new(10).initial_indent(">>>"); // No trailing space
+ assert_eq!(wrapper.fill("foo"), ">>>foo");
+ }
+
+ #[test]
+ fn indent_multiple_lines() {
+ let wrapper = Wrapper::new(6).initial_indent("* ").subsequent_indent(" ");
+ assert_eq!(wrapper.wrap("foo bar baz"), vec!["* foo", " bar", " baz"]);
+ }
+
+ #[test]
+ fn indent_break_words() {
+ let wrapper = Wrapper::new(5).initial_indent("* ").subsequent_indent(" ");
+ assert_eq!(wrapper.wrap("foobarbaz"), vec!["* foo", " bar", " baz"]);
+ }
+
+ #[test]
+ fn hyphens() {
+ assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]);
+ }
+
+ #[test]
+ fn trailing_hyphen() {
+ let wrapper = Wrapper::new(5).break_words(false);
+ assert_eq!(wrapper.wrap("foobar-"), vec!["foobar-"]);
+ }
+
+ #[test]
+ fn multiple_hyphens() {
+ assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]);
+ }
+
+ #[test]
+ fn hyphens_flag() {
+ let wrapper = Wrapper::new(5).break_words(false);
+ assert_eq!(
+ wrapper.wrap("The --foo-bar flag."),
+ vec!["The", "--foo-", "bar", "flag."]
+ );
+ }
+
+ #[test]
+ fn repeated_hyphens() {
+ let wrapper = Wrapper::new(4).break_words(false);
+ assert_eq!(wrapper.wrap("foo--bar"), vec!["foo--bar"]);
+ }
+
+ #[test]
+ fn hyphens_alphanumeric() {
+ assert_eq!(wrap("Na2-CH4", 5), vec!["Na2-", "CH4"]);
+ }
+
+ #[test]
+ fn hyphens_non_alphanumeric() {
+ let wrapper = Wrapper::new(5).break_words(false);
+ assert_eq!(wrapper.wrap("foo(-)bar"), vec!["foo(-)bar"]);
+ }
+
+ #[test]
+ fn multiple_splits() {
+ assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]);
+ }
+
+ #[test]
+ fn forced_split() {
+ let wrapper = Wrapper::new(5).break_words(false);
+ assert_eq!(wrapper.wrap("foobar-baz"), vec!["foobar-", "baz"]);
+ }
+
+ #[test]
+ fn no_hyphenation() {
+ let wrapper = Wrapper::with_splitter(8, NoHyphenation);
+ assert_eq!(wrapper.wrap("foo bar-baz"), vec!["foo", "bar-baz"]);
+ }
+
+ #[test]
+ #[cfg(feature = "hyphenation")]
+ fn auto_hyphenation() {
+ let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
+ let wrapper = Wrapper::new(10);
+ assert_eq!(
+ wrapper.wrap("Internationalization"),
+ vec!["Internatio", "nalization"]
+ );
+
+ let wrapper = Wrapper::with_splitter(10, dictionary);
+ assert_eq!(
+ wrapper.wrap("Internationalization"),
+ vec!["Interna-", "tionaliza-", "tion"]
+ );
+ }
+
+ #[test]
+ #[cfg(feature = "hyphenation")]
+ fn split_len_hyphenation() {
+ // Test that hyphenation takes the width of the wihtespace
+ // into account.
+ let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
+ let wrapper = Wrapper::with_splitter(15, dictionary);
+ assert_eq!(
+ wrapper.wrap("garbage collection"),
+ vec!["garbage col-", "lection"]
+ );
+ }
+
+ #[test]
+ #[cfg(feature = "hyphenation")]
+ fn borrowed_lines() {
+ // Lines that end with an extra hyphen are owned, the final
+ // line is borrowed.
+ use std::borrow::Cow::{Borrowed, Owned};
+ let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
+ let wrapper = Wrapper::with_splitter(10, dictionary);
+ let lines = wrapper.wrap("Internationalization");
+ if let Borrowed(s) = lines[0] {
+ assert!(false, "should not have been borrowed: {:?}", s);
+ }
+ if let Borrowed(s) = lines[1] {
+ assert!(false, "should not have been borrowed: {:?}", s);
+ }
+ if let Owned(ref s) = lines[2] {
+ assert!(false, "should not have been owned: {:?}", s);
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "hyphenation")]
+ fn auto_hyphenation_with_hyphen() {
+ let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
+ let wrapper = Wrapper::new(8).break_words(false);
+ assert_eq!(wrapper.wrap("over-caffinated"), vec!["over-", "caffinated"]);
+
+ let wrapper = Wrapper::with_splitter(8, dictionary).break_words(false);
+ assert_eq!(
+ wrapper.wrap("over-caffinated"),
+ vec!["over-", "caffi-", "nated"]
+ );
+ }
+
+ #[test]
+ fn break_words() {
+ assert_eq!(wrap("foobarbaz", 3), vec!["foo", "bar", "baz"]);
+ }
+
+ #[test]
+ fn break_words_wide_characters() {
+ assert_eq!(wrap("Hello", 5), vec!["He", "ll", "o"]);
+ }
+
+ #[test]
+ fn break_words_zero_width() {
+ assert_eq!(wrap("foobar", 0), vec!["f", "o", "o", "b", "a", "r"]);
+ }
+
+ #[test]
+ fn break_words_line_breaks() {
+ assert_eq!(fill("ab\ncdefghijkl", 5), "ab\ncdefg\nhijkl");
+ assert_eq!(fill("abcdefgh\nijkl", 5), "abcde\nfgh\nijkl");
+ }
+
+ #[test]
+ fn preserve_line_breaks() {
+ assert_eq!(fill("test\n", 11), "test\n");
+ assert_eq!(fill("test\n\na\n\n", 11), "test\n\na\n\n");
+ assert_eq!(fill("1 3 5 7\n1 3 5 7", 7), "1 3 5 7\n1 3 5 7");
+ }
+
+ #[test]
+ fn wrap_preserve_line_breaks() {
+ assert_eq!(fill("1 3 5 7\n1 3 5 7", 5), "1 3 5\n7\n1 3 5\n7");
+ }
+
+ #[test]
+ fn non_breaking_space() {
+ let wrapper = Wrapper::new(5).break_words(false);
+ assert_eq!(wrapper.fill("foo bar baz"), "foo bar baz");
+ }
+
+ #[test]
+ fn non_breaking_hyphen() {
+ let wrapper = Wrapper::new(5).break_words(false);
+ assert_eq!(wrapper.fill("foo‑bar‑baz"), "foo‑bar‑baz");
+ }
+
+ #[test]
+ fn fill_simple() {
+ assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz");
+ }
+}
diff --git a/textwrap/src/splitting.rs b/textwrap/src/splitting.rs
new file mode 100644
index 0000000..f6b65af
--- /dev/null
+++ b/textwrap/src/splitting.rs
@@ -0,0 +1,139 @@
+//! Word splitting functionality.
+//!
+//! To wrap text into lines, long words sometimes need to be split
+//! across lines. The [`WordSplitter`] trait defines this
+//! functionality. [`HyphenSplitter`] is the default implementation of
+//! this treat: it will simply split words on existing hyphens.
+
+#[cfg(feature = "hyphenation")]
+use hyphenation::{Hyphenator, Standard};
+
+/// An interface for splitting words.
+///
+/// When the [`wrap_iter`] method will try to fit text into a line, it
+/// will eventually find a word that it too large the current text
+/// width. It will then call the currently configured `WordSplitter` to
+/// have it attempt to split the word into smaller parts. This trait
+/// describes that functionality via the [`split`] method.
+///
+/// If the `textwrap` crate has been compiled with the `hyphenation`
+/// feature enabled, you will find an implementation of `WordSplitter`
+/// by the `hyphenation::language::Corpus` struct. Use this struct for
+/// language-aware hyphenation. See the [`hyphenation` documentation]
+/// for details.
+///
+/// [`wrap_iter`]: ../struct.Wrapper.html#method.wrap_iter
+/// [`split`]: #tymethod.split
+/// [`hyphenation` documentation]: https://docs.rs/hyphenation/
+pub trait WordSplitter {
+ /// Return all possible splits of word. Each split is a triple
+ /// with a head, a hyphen, and a tail where `head + &hyphen +
+ /// &tail == word`. The hyphen can be empty if there is already a
+ /// hyphen in the head.
+ ///
+ /// The splits should go from smallest to longest and should
+ /// include no split at all. So the word "technology" could be
+ /// split into
+ ///
+ /// ```no_run
+ /// vec![("tech", "-", "nology"),
+ /// ("technol", "-", "ogy"),
+ /// ("technolo", "-", "gy"),
+ /// ("technology", "", "")];
+ /// ```
+ fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)>;
+}
+
+/// Use this as a [`Wrapper.splitter`] to avoid any kind of
+/// hyphenation:
+///
+/// ```
+/// use textwrap::{Wrapper, NoHyphenation};
+///
+/// let wrapper = Wrapper::with_splitter(8, NoHyphenation);
+/// assert_eq!(wrapper.wrap("foo bar-baz"), vec!["foo", "bar-baz"]);
+/// ```
+///
+/// [`Wrapper.splitter`]: ../struct.Wrapper.html#structfield.splitter
+#[derive(Clone, Debug)]
+pub struct NoHyphenation;
+
+/// `NoHyphenation` implements `WordSplitter` by not splitting the
+/// word at all.
+impl WordSplitter for NoHyphenation {
+ fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> {
+ vec![(word, "", "")]
+ }
+}
+
+/// Simple and default way to split words: splitting on existing
+/// hyphens only.
+///
+/// You probably don't need to use this type since it's already used
+/// by default by `Wrapper::new`.
+#[derive(Clone, Debug)]
+pub struct HyphenSplitter;
+
+/// `HyphenSplitter` is the default `WordSplitter` used by
+/// `Wrapper::new`. It will split words on any existing hyphens in the
+/// word.
+///
+/// It will only use hyphens that are surrounded by alphanumeric
+/// characters, which prevents a word like "--foo-bar" from being
+/// split on the first or second hyphen.
+impl WordSplitter for HyphenSplitter {
+ fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> {
+ let mut triples = Vec::new();
+ // Split on hyphens, smallest split first. We only use hyphens
+ // that are surrounded by alphanumeric characters. This is to
+ // avoid splitting on repeated hyphens, such as those found in
+ // --foo-bar.
+ let mut char_indices = word.char_indices();
+ // Early return if the word is empty.
+ let mut prev = match char_indices.next() {
+ None => return vec![(word, "", "")],
+ Some((_, ch)) => ch,
+ };
+
+ // Find current word, or return early if the word only has a
+ // single character.
+ let (mut idx, mut cur) = match char_indices.next() {
+ None => return vec![(word, "", "")],
+ Some((idx, cur)) => (idx, cur),
+ };
+
+ for (i, next) in char_indices {
+ if prev.is_alphanumeric() && cur == '-' && next.is_alphanumeric() {
+ let (head, tail) = word.split_at(idx + 1);
+ triples.push((head, "", tail));
+ }
+ prev = cur;
+ idx = i;
+ cur = next;
+ }
+
+ // Finally option is no split at all.
+ triples.push((word, "", ""));
+
+ triples
+ }
+}
+
+/// A hyphenation dictionary can be used to do language-specific
+/// hyphenation using patterns from the hyphenation crate.
+#[cfg(feature = "hyphenation")]
+impl WordSplitter for Standard {
+ fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> {
+ // Find splits based on language dictionary.
+ let mut triples = Vec::new();
+ for n in self.hyphenate(word).breaks {
+ let (head, tail) = word.split_at(n);
+ let hyphen = if head.ends_with('-') { "" } else { "-" };
+ triples.push((head, hyphen, tail));
+ }
+ // Finally option is no split at all.
+ triples.push((word, "", ""));
+
+ triples
+ }
+}
diff --git a/textwrap/tests/version-numbers.rs b/textwrap/tests/version-numbers.rs
new file mode 100644
index 0000000..85c52e3
--- /dev/null
+++ b/textwrap/tests/version-numbers.rs
@@ -0,0 +1,17 @@
+#[macro_use]
+extern crate version_sync;
+
+#[test]
+fn test_readme_deps() {
+ assert_markdown_deps_updated!("README.md");
+}
+
+#[test]
+fn test_readme_changelog() {
+ assert_contains_regex!("README.md", r"^### Version {version} — .* \d\d?.., 20\d\d$");
+}
+
+#[test]
+fn test_html_root_url() {
+ assert_html_root_url_updated!("src/lib.rs");
+}
diff --git a/unicode-segmentation/.gitignore b/unicode-segmentation/.gitignore
new file mode 100644
index 0000000..ec1ef20
--- /dev/null
+++ b/unicode-segmentation/.gitignore
@@ -0,0 +1,5 @@
+target
+Cargo.lock
+scripts/tmp
+*.pyc
+*.txt
diff --git a/unicode-segmentation/.travis.yml b/unicode-segmentation/.travis.yml
new file mode 100644
index 0000000..af011bd
--- /dev/null
+++ b/unicode-segmentation/.travis.yml
@@ -0,0 +1,24 @@
+language: rust
+rust:
+ - 1.24.0
+ - stable
+os: linux
+script:
+ - cargo build --verbose
+ - |
+ if [ $TRAVIS_RUST_VERSION = stable ]; then cargo test --verbose || travis_terminate 1; fi
+ - cargo doc
+after_success: |
+ [ $TRAVIS_RUST_VERSION = stable ] &&
+ [ $TRAVIS_BRANCH = master ] &&
+ [ $TRAVIS_PULL_REQUEST = false ] &&
+ echo '<meta http-equiv=refresh content=0;url=unicode_segmentation/index.html>' > target/doc/index.html &&
+ pip install ghp-import --user &&
+ $HOME/.local/bin/ghp-import -n target/doc &&
+ git push -qf https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
+env:
+ global:
+ secure: d3xB8MAHhj88le5WjaDmIsharVeZ+eDIbQtuPEkg5VjIsD+ZOc9ZY/y1Nrz3q8Xh3ytjYv78IWmxwn8UsRhimCZbgR4V4xkz8hSgIGn9dFbOvIpbeg6Tfvu2UO2YUOcNc/WtI/uymaMuZ2g8Fcg7K2ITEO2lXAcOFRpnBh2dXmA=
+notifications:
+ email:
+ on_success: never
diff --git a/unicode-segmentation/COPYRIGHT b/unicode-segmentation/COPYRIGHT
new file mode 100644
index 0000000..b286ec1
--- /dev/null
+++ b/unicode-segmentation/COPYRIGHT
@@ -0,0 +1,7 @@
+Licensed under the Apache License, Version 2.0
+<LICENSE-APACHE or
+http://www.apache.org/licenses/LICENSE-2.0> or the MIT
+license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
+at your option. All files in the project carrying such
+notice may not be copied, modified, or distributed except
+according to those terms.
diff --git a/unicode-segmentation/Cargo.toml b/unicode-segmentation/Cargo.toml
new file mode 100644
index 0000000..c513e11
--- /dev/null
+++ b/unicode-segmentation/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+
+name = "unicode-segmentation"
+version = "1.6.0"
+authors = ["kwantam <kwantam@gmail.com>", "Manish Goregaokar <manishsmail@gmail.com>"]
+
+homepage = "https://github.com/unicode-rs/unicode-segmentation"
+repository = "https://github.com/unicode-rs/unicode-segmentation"
+documentation = "https://unicode-rs.github.io/unicode-segmentation"
+
+license = "MIT/Apache-2.0"
+keywords = ["text", "unicode", "grapheme", "word", "boundary"]
+readme = "README.md"
+description = """
+This crate provides Grapheme Cluster, Word and Sentence boundaries
+according to Unicode Standard Annex #29 rules.
+"""
+
+exclude = [ "target/*", "Cargo.lock", "scripts/tmp", "*.txt" ]
+
+[features]
+no_std = [] # This is a no-op, preserved for backward compatibility only.
+
+[dev-dependencies]
+quickcheck = "0.7"
diff --git a/unicode-segmentation/LICENSE-APACHE b/unicode-segmentation/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/unicode-segmentation/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/unicode-segmentation/LICENSE-MIT b/unicode-segmentation/LICENSE-MIT
new file mode 100644
index 0000000..e69282e
--- /dev/null
+++ b/unicode-segmentation/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015 The Rust Project Developers
+
+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/unicode-segmentation/README.md b/unicode-segmentation/README.md
new file mode 100644
index 0000000..08fe6b8
--- /dev/null
+++ b/unicode-segmentation/README.md
@@ -0,0 +1,89 @@
+Iterators which split strings on Grapheme Cluster or Word boundaries, according
+to the [Unicode Standard Annex #29](http://www.unicode.org/reports/tr29/) rules.
+
+[![Build Status](https://travis-ci.org/unicode-rs/unicode-segmentation.svg)](https://travis-ci.org/unicode-rs/unicode-segmentation)
+
+[Documentation](https://unicode-rs.github.io/unicode-segmentation/unicode_segmentation/index.html)
+
+```rust
+use unicode_segmentation::UnicodeSegmentation;
+
+fn main() {
+ let s = "a̐éö̲\r\n";
+ let g = UnicodeSegmentation::graphemes(s, true).collect::<Vec<&str>>();
+ let b: &[_] = &["a̐", "é", "ö̲", "\r\n"];
+ assert_eq!(g, b);
+
+ let s = "The quick (\"brown\") fox can't jump 32.3 feet, right?";
+ let w = s.unicode_words().collect::<Vec<&str>>();
+ let b: &[_] = &["The", "quick", "brown", "fox", "can't", "jump", "32.3", "feet", "right"];
+ assert_eq!(w, b);
+
+ let s = "The quick (\"brown\") fox";
+ let w = s.split_word_bounds().collect::<Vec<&str>>();
+ let b: &[_] = &["The", " ", "quick", " ", "(", "\"", "brown", "\"", ")", " ", " ", "fox"];
+ assert_eq!(w, b);
+}
+```
+
+# no_std
+
+unicode-segmentation does not depend on libstd, so it can be used in crates
+with the `#![no_std]` attribute.
+
+# crates.io
+
+You can use this package in your project by adding the following
+to your `Cargo.toml`:
+
+```toml
+[dependencies]
+unicode-segmentation = "1.3.0"
+```
+
+# Change Log
+
+## 1.6.0
+
+* [#72](https://github.com/unicode-rs/unicode-segmentation/pull/72) Upgrade to Unicode 12
+
+## 1.5.0
+
+* [#68](https://github.com/unicode-rs/unicode-segmentation/pull/68) Upgrade to Unicode 11
+
+## 1.4.0
+
+* [#56](https://github.com/unicode-rs/unicode-segmentation/pull/56) Upgrade to Unicode 10
+
+## 1.3.0
+
+* [#24](https://github.com/unicode-rs/unicode-segmentation/pull/24) Add support for sentence boundaries
+* [#44](https://github.com/unicode-rs/unicode-segmentation/pull/44) Treat `gc=No` as a subset of `gc=N`
+
+## 1.2.1
+
+* [#37](https://github.com/unicode-rs/unicode-segmentation/pull/37):
+ Fix panic in `provide_context`.
+* [#40](https://github.com/unicode-rs/unicode-segmentation/pull/40):
+ Fix crash in `prev_boundary`.
+
+## 1.2.0
+
+* New `GraphemeCursor` API allows random access and bidirectional iteration.
+* Fixed incorrect splitting of certain emoji modifier sequences.
+
+## 1.1.0
+
+* Add `as_str` methods to the iterator types.
+
+## 1.0.3
+
+* Code cleanup and additional tests.
+
+## 1.0.1
+
+* Fix a bug affecting some grapheme clusters containing Prepend characters.
+
+## 1.0.0
+
+* Upgrade to Unicode 9.0.0.
diff --git a/unicode-segmentation/scripts/unicode.py b/unicode-segmentation/scripts/unicode.py
new file mode 100755
index 0000000..580b3c0
--- /dev/null
+++ b/unicode-segmentation/scripts/unicode.py
@@ -0,0 +1,375 @@
+#!/usr/bin/env python
+#
+# Copyright 2011-2015 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+# This script uses the following Unicode tables:
+# - DerivedCoreProperties.txt
+# - auxiliary/GraphemeBreakProperty.txt
+# - auxiliary/WordBreakProperty.txt
+# - ReadMe.txt
+# - UnicodeData.txt
+#
+# Since this should not require frequent updates, we just store this
+# out-of-line and check the unicode.rs file into git.
+
+import fileinput, re, os, sys
+
+preamble = '''// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly
+
+#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
+'''
+
+# Mapping taken from Table 12 from:
+# http://www.unicode.org/reports/tr44/#General_Category_Values
+expanded_categories = {
+ 'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'],
+ 'Lm': ['L'], 'Lo': ['L'],
+ 'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'],
+ 'Nd': ['N'], 'Nl': ['N'], 'No': ['N'],
+ 'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'],
+ 'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'],
+ 'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'],
+ 'Zs': ['Z'], 'Zl': ['Z'], 'Zp': ['Z'],
+ 'Cc': ['C'], 'Cf': ['C'], 'Cs': ['C'], 'Co': ['C'], 'Cn': ['C'],
+}
+
+# these are the surrogate codepoints, which are not valid rust characters
+surrogate_codepoints = (0xd800, 0xdfff)
+
+UNICODE_VERSION = (12, 0, 0)
+
+UNICODE_VERSION_NUMBER = "%s.%s.%s" %UNICODE_VERSION
+
+def is_surrogate(n):
+ return surrogate_codepoints[0] <= n <= surrogate_codepoints[1]
+
+def fetch(f):
+ if not os.path.exists(os.path.basename(f)):
+ if "emoji" in f:
+ os.system("curl -O https://www.unicode.org/Public/emoji/%s.%s/%s"
+ % (UNICODE_VERSION[0], UNICODE_VERSION[1], f))
+ else:
+ os.system("curl -O http://www.unicode.org/Public/%s/ucd/%s"
+ % (UNICODE_VERSION_NUMBER, f))
+
+ if not os.path.exists(os.path.basename(f)):
+ sys.stderr.write("cannot load %s" % f)
+ exit(1)
+
+def load_gencats(f):
+ fetch(f)
+ gencats = {}
+
+ udict = {};
+ range_start = -1;
+ for line in fileinput.input(f):
+ data = line.split(';');
+ if len(data) != 15:
+ continue
+ cp = int(data[0], 16);
+ if is_surrogate(cp):
+ continue
+ if range_start >= 0:
+ for i in range(range_start, cp):
+ udict[i] = data;
+ range_start = -1;
+ if data[1].endswith(", First>"):
+ range_start = cp;
+ continue;
+ udict[cp] = data;
+
+ for code in udict:
+ [code_org, name, gencat, combine, bidi,
+ decomp, deci, digit, num, mirror,
+ old, iso, upcase, lowcase, titlecase ] = udict[code];
+
+ # place letter in categories as appropriate
+ for cat in [gencat, "Assigned"] + expanded_categories.get(gencat, []):
+ if cat not in gencats:
+ gencats[cat] = []
+ gencats[cat].append(code)
+
+ gencats = group_cats(gencats)
+ return gencats
+
+def group_cats(cats):
+ cats_out = {}
+ for cat in cats:
+ cats_out[cat] = group_cat(cats[cat])
+ return cats_out
+
+def group_cat(cat):
+ cat_out = []
+ letters = sorted(set(cat))
+ cur_start = letters.pop(0)
+ cur_end = cur_start
+ for letter in letters:
+ assert letter > cur_end, \
+ "cur_end: %s, letter: %s" % (hex(cur_end), hex(letter))
+ if letter == cur_end + 1:
+ cur_end = letter
+ else:
+ cat_out.append((cur_start, cur_end))
+ cur_start = cur_end = letter
+ cat_out.append((cur_start, cur_end))
+ return cat_out
+
+def ungroup_cat(cat):
+ cat_out = []
+ for (lo, hi) in cat:
+ while lo <= hi:
+ cat_out.append(lo)
+ lo += 1
+ return cat_out
+
+def format_table_content(f, content, indent):
+ line = " "*indent
+ first = True
+ for chunk in content.split(","):
+ if len(line) + len(chunk) < 98:
+ if first:
+ line += chunk
+ else:
+ line += ", " + chunk
+ first = False
+ else:
+ f.write(line + ",\n")
+ line = " "*indent + chunk
+ f.write(line)
+
+def load_properties(f, interestingprops):
+ fetch(f)
+ props = {}
+ re1 = re.compile(r"^ *([0-9A-F]+) *; *(\w+)")
+ re2 = re.compile(r"^ *([0-9A-F]+)\.\.([0-9A-F]+) *; *(\w+)")
+
+ for line in fileinput.input(os.path.basename(f)):
+ prop = None
+ d_lo = 0
+ d_hi = 0
+ m = re1.match(line)
+ if m:
+ d_lo = m.group(1)
+ d_hi = m.group(1)
+ prop = m.group(2)
+ else:
+ m = re2.match(line)
+ if m:
+ d_lo = m.group(1)
+ d_hi = m.group(2)
+ prop = m.group(3)
+ else:
+ continue
+ if interestingprops and prop not in interestingprops:
+ continue
+ d_lo = int(d_lo, 16)
+ d_hi = int(d_hi, 16)
+ if prop not in props:
+ props[prop] = []
+ props[prop].append((d_lo, d_hi))
+
+ # optimize if possible
+ for prop in props:
+ props[prop] = group_cat(ungroup_cat(props[prop]))
+
+ return props
+
+def escape_char(c):
+ return "'\\u{%x}'" % c
+
+def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True,
+ pfun=lambda x: "(%s,%s)" % (escape_char(x[0]), escape_char(x[1])), is_const=True):
+ pub_string = "const"
+ if not is_const:
+ pub_string = "let"
+ if is_pub:
+ pub_string = "pub " + pub_string
+ f.write(" %s %s: %s = &[\n" % (pub_string, name, t_type))
+ data = ""
+ first = True
+ for dat in t_data:
+ if not first:
+ data += ","
+ first = False
+ data += pfun(dat)
+ format_table_content(f, data, 8)
+ f.write("\n ];\n\n")
+
+def emit_util_mod(f):
+ f.write("""
+pub mod util {
+ #[inline]
+ pub fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ r.binary_search_by(|&(lo,hi)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }).is_ok()
+ }
+
+ #[inline]
+ fn is_alphabetic(c: char) -> bool {
+ match c {
+ 'a' ... 'z' | 'A' ... 'Z' => true,
+ c if c > '\x7f' => super::derived_property::Alphabetic(c),
+ _ => false,
+ }
+ }
+
+ #[inline]
+ fn is_numeric(c: char) -> bool {
+ match c {
+ '0' ... '9' => true,
+ c if c > '\x7f' => super::general_category::N(c),
+ _ => false,
+ }
+ }
+
+ #[inline]
+ pub fn is_alphanumeric(c: char) -> bool {
+ is_alphabetic(c) || is_numeric(c)
+ }
+}
+
+""")
+
+def emit_property_module(f, mod, tbl, emit):
+ f.write("mod %s {\n" % mod)
+ for cat in sorted(emit):
+ emit_table(f, "%s_table" % cat, tbl[cat], is_pub=False)
+ f.write(" #[inline]\n")
+ f.write(" pub fn %s(c: char) -> bool {\n" % cat)
+ f.write(" super::util::bsearch_range_table(c, %s_table)\n" % cat)
+ f.write(" }\n\n")
+ f.write("}\n\n")
+
+def emit_break_module(f, break_table, break_cats, name):
+ Name = name.capitalize()
+ f.write("""pub mod %s {
+ use core::result::Result::{Ok, Err};
+
+ pub use self::%sCat::*;
+
+ #[allow(non_camel_case_types)]
+ #[derive(Clone, Copy, PartialEq, Eq, Debug)]
+ pub enum %sCat {
+""" % (name, Name, Name))
+
+ break_cats.append("Any")
+ break_cats.sort()
+ for cat in break_cats:
+ f.write((" %sC_" % Name[0]) + cat + ",\n")
+ f.write(""" }
+
+ fn bsearch_range_value_table(c: char, r: &'static [(char, char, %sCat)]) -> %sCat {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ match r.binary_search_by(|&(lo, hi, _)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }) {
+ Ok(idx) => {
+ let (_, _, cat) = r[idx];
+ cat
+ }
+ Err(_) => %sC_Any
+ }
+ }
+
+ pub fn %s_category(c: char) -> %sCat {
+ bsearch_range_value_table(c, %s_cat_table)
+ }
+
+""" % (Name, Name, Name[0], name, Name, name))
+
+ emit_table(f, "%s_cat_table" % name, break_table, "&'static [(char, char, %sCat)]" % Name,
+ pfun=lambda x: "(%s,%s,%sC_%s)" % (escape_char(x[0]), escape_char(x[1]), Name[0], x[2]),
+ is_pub=False, is_const=True)
+ f.write("}\n")
+
+if __name__ == "__main__":
+ r = "tables.rs"
+ if os.path.exists(r):
+ os.remove(r)
+ with open(r, "w") as rf:
+ # write the file's preamble
+ rf.write(preamble)
+ rf.write("""
+/// The version of [Unicode](http://www.unicode.org/)
+/// that this version of unicode-segmentation is based on.
+pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
+""" % UNICODE_VERSION)
+
+ # download and parse all the data
+ gencats = load_gencats("UnicodeData.txt")
+ derived = load_properties("DerivedCoreProperties.txt", ["Alphabetic"])
+
+ emit_util_mod(rf)
+ for (name, cat, pfuns) in ("general_category", gencats, ["N"]), \
+ ("derived_property", derived, ["Alphabetic"]):
+ emit_property_module(rf, name, cat, pfuns)
+
+ ### grapheme cluster module
+ # from http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Break_Property_Values
+ grapheme_cats = load_properties("auxiliary/GraphemeBreakProperty.txt", [])
+
+ # Control
+ # Note:
+ # This category also includes Cs (surrogate codepoints), but Rust's `char`s are
+ # Unicode Scalar Values only, and surrogates are thus invalid `char`s.
+ # Thus, we have to remove Cs from the Control category
+ grapheme_cats["Control"] = group_cat(list(
+ set(ungroup_cat(grapheme_cats["Control"]))
+ - set(ungroup_cat([surrogate_codepoints]))))
+
+ grapheme_table = []
+ for cat in grapheme_cats:
+ grapheme_table.extend([(x, y, cat) for (x, y) in grapheme_cats[cat]])
+ emoji_props = load_properties("emoji-data.txt", ["Extended_Pictographic"])
+ grapheme_table.extend([(x, y, "Extended_Pictographic") for (x, y) in emoji_props["Extended_Pictographic"]])
+ grapheme_table.sort(key=lambda w: w[0])
+ last = -1
+ for chars in grapheme_table:
+ if chars[0] <= last:
+ raise "Grapheme tables and Extended_Pictographic values overlap; need to store these separately!"
+ last = chars[1]
+ emit_break_module(rf, grapheme_table, list(grapheme_cats.keys()) + ["Extended_Pictographic"], "grapheme")
+ rf.write("\n")
+
+ word_cats = load_properties("auxiliary/WordBreakProperty.txt", [])
+ word_table = []
+ for cat in word_cats:
+ word_table.extend([(x, y, cat) for (x, y) in word_cats[cat]])
+ word_table.sort(key=lambda w: w[0])
+ emit_break_module(rf, word_table, list(word_cats.keys()), "word")
+
+ # There are some emoji which are also ALetter, so this needs to be stored separately
+ # For efficiency, we could still merge the two tables and produce an ALetterEP state
+ emoji_table = [(x, y, "Extended_Pictographic") for (x, y) in emoji_props["Extended_Pictographic"]]
+ emit_break_module(rf, emoji_table, ["Extended_Pictographic"], "emoji")
+
+ sentence_cats = load_properties("auxiliary/SentenceBreakProperty.txt", [])
+ sentence_table = []
+ for cat in sentence_cats:
+ sentence_table.extend([(x, y, cat) for (x, y) in sentence_cats[cat]])
+ sentence_table.sort(key=lambda w: w[0])
+ emit_break_module(rf, sentence_table, list(sentence_cats.keys()), "sentence")
diff --git a/unicode-segmentation/scripts/unicode_gen_breaktests.py b/unicode-segmentation/scripts/unicode_gen_breaktests.py
new file mode 100755
index 0000000..113afa9
--- /dev/null
+++ b/unicode-segmentation/scripts/unicode_gen_breaktests.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python
+# -*- coding: utf-8
+#
+# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+# This script uses the following Unicode tables:
+# - auxiliary/GraphemeBreakTest.txt
+# - auxiliary/WordBreakTest.txt
+#
+# Since this should not require frequent updates, we just store this
+# out-of-line and check the unicode.rs file into git.
+from __future__ import print_function
+
+import unicode, re, os, fileinput
+
+def load_test_data(f, optsplit=[]):
+ testRe1 = re.compile(r"^÷\s+([^\s].*[^\s])\s+÷\s+#\s+÷\s+\[0.2\].*?([÷×].*)\s+÷\s+\[0.3\]\s*$")
+
+ unicode.fetch(f)
+ data = []
+ for line in fileinput.input(os.path.basename(f)):
+ # lines that include a test start with the ÷ character
+ if len(line) < 2 or not line.startswith('÷'):
+ continue
+
+ m = testRe1.match(line)
+ if not m:
+ print("error: no match on line where test was expected: %s" % line)
+ continue
+
+ # process the characters in this test case
+ chars = process_split_string(m.group(1))
+ # skip test case if it contains invalid characters (viz., surrogates)
+ if not chars:
+ continue
+
+ # now process test cases
+ (chars, info) = process_split_info(m.group(2), chars, optsplit)
+
+ # make sure that we have break info for each break!
+ assert len(chars) - 1 == len(info)
+
+ data.append((chars, info))
+
+ return data
+
+def process_split_info(s, c, o):
+ outcs = []
+ outis = []
+ workcs = c.pop(0)
+
+ # are we on a × or a ÷?
+ isX = False
+ if s.startswith('×'):
+ isX = True
+
+ # find each instance of '(÷|×) [x.y] '
+ while s:
+ # find the currently considered rule number
+ sInd = s.index('[') + 1
+ eInd = s.index(']')
+
+ # if it's '× [a.b]' where 'a.b' is in o, then
+ # we consider it a split even though it's not
+ # marked as one
+ # if it's ÷ then it's always a split
+ if not isX or s[sInd:eInd] in o:
+ outis.append(s[sInd:eInd])
+ outcs.append(workcs)
+ workcs = c.pop(0)
+ else:
+ workcs.extend(c.pop(0))
+
+ idx = 1
+ while idx < len(s):
+ if s[idx:].startswith('×'):
+ isX = True
+ break
+ if s[idx:].startswith('÷'):
+ isX = False
+ break
+ idx += 1
+ s = s[idx:]
+
+ outcs.append(workcs)
+ return (outcs, outis)
+
+def process_split_string(s):
+ outls = []
+ workls = []
+
+ inls = s.split()
+
+ for i in inls:
+ if i == '÷' or i == '×':
+ outls.append(workls)
+ workls = []
+ continue
+
+ ival = int(i,16)
+
+ if unicode.is_surrogate(ival):
+ return []
+
+ workls.append(ival)
+
+ if workls:
+ outls.append(workls)
+
+ return outls
+
+def showfun(x):
+ outstr = '("'
+ for c in x[0]:
+ outstr += "\\u{%x}" % c
+ outstr += '",&['
+ xfirst = True
+ for xx in x[1:]:
+ if not xfirst:
+ outstr += '],&['
+ xfirst = False
+ sfirst = True
+ for sp in xx:
+ if not sfirst:
+ outstr += ','
+ sfirst = False
+ outstr += '"'
+ for c in sp:
+ outstr += "\\u{%x}" % c
+ outstr += '"'
+ outstr += '])'
+ return outstr
+
+def create_grapheme_data(f):
+ # rules 9.1 and 9.2 are for extended graphemes only
+ optsplits = ['9.1','9.2']
+ d = load_test_data("auxiliary/GraphemeBreakTest.txt", optsplits)
+
+ test_same = []
+ test_diff = []
+
+ for (c, i) in d:
+ allchars = [cn for s in c for cn in s]
+ extgraphs = []
+ extwork = []
+
+ extwork.extend(c[0])
+ for n in range(0,len(i)):
+ if i[n] in optsplits:
+ extwork.extend(c[n+1])
+ else:
+ extgraphs.append(extwork)
+ extwork = []
+ extwork.extend(c[n+1])
+
+ # these are the extended grapheme clusters
+ extgraphs.append(extwork)
+
+ if extgraphs == c:
+ test_same.append((allchars, c))
+ else:
+ test_diff.append((allchars, extgraphs, c))
+
+ stype = "&'static [(&'static str, &'static [&'static str])]"
+ dtype = "&'static [(&'static str, &'static [&'static str], &'static [&'static str])]"
+ f.write(" // official Unicode test data\n")
+ f.write(" // http://www.unicode.org/Public/%s/ucd/auxiliary/GraphemeBreakTest.txt\n" % unicode.UNICODE_VERSION_NUMBER)
+ unicode.emit_table(f, "TEST_SAME", test_same, stype, True, showfun, True)
+ unicode.emit_table(f, "TEST_DIFF", test_diff, dtype, True, showfun, True)
+
+def create_words_data(f):
+ d = load_test_data("auxiliary/WordBreakTest.txt")
+
+ test = []
+
+ for (c, i) in d:
+ allchars = [cn for s in c for cn in s]
+ test.append((allchars, c))
+
+ wtype = "&'static [(&'static str, &'static [&'static str])]"
+ f.write(" // official Unicode test data\n")
+ f.write(" // http://www.unicode.org/Public/%s/ucd/auxiliary/WordBreakTest.txt\n" % unicode.UNICODE_VERSION_NUMBER)
+ unicode.emit_table(f, "TEST_WORD", test, wtype, True, showfun, True)
+
+def create_sentence_data(f):
+ d = load_test_data("auxiliary/SentenceBreakTest.txt")
+
+ test = []
+
+ for (c, i) in d:
+ allchars = [cn for s in c for cn in s]
+ test.append((allchars, c))
+
+ wtype = "&'static [(&'static str, &'static [&'static str])]"
+ f.write(" // official Unicode test data\n")
+ f.write(" // http://www.unicode.org/Public/%s/ucd/auxiliary/SentenceBreakTest.txt\n" % unicode.UNICODE_VERSION_NUMBER)
+ unicode.emit_table(f, "TEST_SENTENCE", test, wtype, True, showfun, True)
+
+if __name__ == "__main__":
+ with open("testdata.rs", "w") as rf:
+ rf.write(unicode.preamble)
+ create_grapheme_data(rf)
+ create_words_data(rf)
+ create_sentence_data(rf)
diff --git a/unicode-segmentation/src/grapheme.rs b/unicode-segmentation/src/grapheme.rs
new file mode 100644
index 0000000..cde6526
--- /dev/null
+++ b/unicode-segmentation/src/grapheme.rs
@@ -0,0 +1,708 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::cmp;
+
+use tables::grapheme::GraphemeCat;
+
+/// External iterator for grapheme clusters and byte offsets.
+#[derive(Clone)]
+pub struct GraphemeIndices<'a> {
+ start_offset: usize,
+ iter: Graphemes<'a>,
+}
+
+impl<'a> GraphemeIndices<'a> {
+ #[inline]
+ /// View the underlying data (the part yet to be iterated) as a slice of the original string.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::UnicodeSegmentation;
+ /// let mut iter = "abc".grapheme_indices(true);
+ /// assert_eq!(iter.as_str(), "abc");
+ /// iter.next();
+ /// assert_eq!(iter.as_str(), "bc");
+ /// iter.next();
+ /// iter.next();
+ /// assert_eq!(iter.as_str(), "");
+ /// ```
+ pub fn as_str(&self) -> &'a str {
+ self.iter.as_str()
+ }
+}
+
+impl<'a> Iterator for GraphemeIndices<'a> {
+ type Item = (usize, &'a str);
+
+ #[inline]
+ fn next(&mut self) -> Option<(usize, &'a str)> {
+ self.iter.next().map(|s| (s.as_ptr() as usize - self.start_offset, s))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl<'a> DoubleEndedIterator for GraphemeIndices<'a> {
+ #[inline]
+ fn next_back(&mut self) -> Option<(usize, &'a str)> {
+ self.iter.next_back().map(|s| (s.as_ptr() as usize - self.start_offset, s))
+ }
+}
+
+/// External iterator for a string's
+/// [grapheme clusters](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries).
+#[derive(Clone)]
+pub struct Graphemes<'a> {
+ string: &'a str,
+ cursor: GraphemeCursor,
+ cursor_back: GraphemeCursor,
+}
+
+impl<'a> Graphemes<'a> {
+ #[inline]
+ /// View the underlying data (the part yet to be iterated) as a slice of the original string.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::UnicodeSegmentation;
+ /// let mut iter = "abc".graphemes(true);
+ /// assert_eq!(iter.as_str(), "abc");
+ /// iter.next();
+ /// assert_eq!(iter.as_str(), "bc");
+ /// iter.next();
+ /// iter.next();
+ /// assert_eq!(iter.as_str(), "");
+ /// ```
+ pub fn as_str(&self) -> &'a str {
+ &self.string[self.cursor.cur_cursor()..self.cursor_back.cur_cursor()]
+ }
+}
+
+impl<'a> Iterator for Graphemes<'a> {
+ type Item = &'a str;
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let slen = self.cursor_back.cur_cursor() - self.cursor.cur_cursor();
+ (cmp::min(slen, 1), Some(slen))
+ }
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a str> {
+ let start = self.cursor.cur_cursor();
+ if start == self.cursor_back.cur_cursor() {
+ return None;
+ }
+ let next = self.cursor.next_boundary(self.string, 0).unwrap().unwrap();
+ Some(&self.string[start..next])
+ }
+}
+
+impl<'a> DoubleEndedIterator for Graphemes<'a> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a str> {
+ let end = self.cursor_back.cur_cursor();
+ if end == self.cursor.cur_cursor() {
+ return None;
+ }
+ let prev = self.cursor_back.prev_boundary(self.string, 0).unwrap().unwrap();
+ Some(&self.string[prev..end])
+ }
+}
+
+#[inline]
+pub fn new_graphemes<'b>(s: &'b str, is_extended: bool) -> Graphemes<'b> {
+ let len = s.len();
+ Graphemes {
+ string: s,
+ cursor: GraphemeCursor::new(0, len, is_extended),
+ cursor_back: GraphemeCursor::new(len, len, is_extended),
+ }
+}
+
+#[inline]
+pub fn new_grapheme_indices<'b>(s: &'b str, is_extended: bool) -> GraphemeIndices<'b> {
+ GraphemeIndices { start_offset: s.as_ptr() as usize, iter: new_graphemes(s, is_extended) }
+}
+
+// maybe unify with PairResult?
+// An enum describing information about a potential boundary.
+#[derive(PartialEq, Eq, Clone)]
+enum GraphemeState {
+ // No information is known.
+ Unknown,
+ // It is known to not be a boundary.
+ NotBreak,
+ // It is known to be a boundary.
+ Break,
+ // The codepoint after is a Regional Indicator Symbol, so a boundary iff
+ // it is preceded by an even number of RIS codepoints. (GB12, GB13)
+ Regional,
+ // The codepoint after is Extended_Pictographic,
+ // so whether it's a boundary depends on pre-context according to GB11.
+ Emoji,
+}
+
+/// Cursor-based segmenter for grapheme clusters.
+#[derive(Clone)]
+pub struct GraphemeCursor {
+ // Current cursor position.
+ offset: usize,
+ // Total length of the string.
+ len: usize,
+ // A config flag indicating whether this cursor computes legacy or extended
+ // grapheme cluster boundaries (enables GB9a and GB9b if set).
+ is_extended: bool,
+ // Information about the potential boundary at `offset`
+ state: GraphemeState,
+ // Category of codepoint immediately preceding cursor, if known.
+ cat_before: Option<GraphemeCat>,
+ // Category of codepoint immediately after cursor, if known.
+ cat_after: Option<GraphemeCat>,
+ // If set, at least one more codepoint immediately preceding this offset
+ // is needed to resolve whether there's a boundary at `offset`.
+ pre_context_offset: Option<usize>,
+ // The number of RIS codepoints preceding `offset`. If `pre_context_offset`
+ // is set, then counts the number of RIS between that and `offset`, otherwise
+ // is an accurate count relative to the string.
+ ris_count: Option<usize>,
+ // Set if a call to `prev_boundary` or `next_boundary` was suspended due
+ // to needing more input.
+ resuming: bool,
+}
+
+/// An error return indicating that not enough content was available in the
+/// provided chunk to satisfy the query, and that more content must be provided.
+#[derive(PartialEq, Eq, Debug)]
+pub enum GraphemeIncomplete {
+ /// More pre-context is needed. The caller should call `provide_context`
+ /// with a chunk ending at the offset given, then retry the query. This
+ /// will only be returned if the `chunk_start` parameter is nonzero.
+ PreContext(usize),
+
+ /// When requesting `prev_boundary`, the cursor is moving past the beginning
+ /// of the current chunk, so the chunk before that is requested. This will
+ /// only be returned if the `chunk_start` parameter is nonzero.
+ PrevChunk,
+
+ /// When requesting `next_boundary`, the cursor is moving past the end of the
+ /// current chunk, so the chunk after that is requested. This will only be
+ /// returned if the chunk ends before the `len` parameter provided on
+ /// creation of the cursor.
+ NextChunk, // requesting chunk following the one given
+
+ /// An error returned when the chunk given does not contain the cursor position.
+ InvalidOffset,
+}
+
+// An enum describing the result from lookup of a pair of categories.
+#[derive(PartialEq, Eq)]
+enum PairResult {
+ NotBreak, // definitely not a break
+ Break, // definitely a break
+ Extended, // a break iff not in extended mode
+ Regional, // a break if preceded by an even number of RIS
+ Emoji, // a break if preceded by emoji base and (Extend)*
+}
+
+fn check_pair(before: GraphemeCat, after: GraphemeCat) -> PairResult {
+ use tables::grapheme::GraphemeCat::*;
+ use self::PairResult::*;
+ match (before, after) {
+ (GC_CR, GC_LF) => NotBreak, // GB3
+ (GC_Control, _) => Break, // GB4
+ (GC_CR, _) => Break, // GB4
+ (GC_LF, _) => Break, // GB4
+ (_, GC_Control) => Break, // GB5
+ (_, GC_CR) => Break, // GB5
+ (_, GC_LF) => Break, // GB5
+ (GC_L, GC_L) => NotBreak, // GB6
+ (GC_L, GC_V) => NotBreak, // GB6
+ (GC_L, GC_LV) => NotBreak, // GB6
+ (GC_L, GC_LVT) => NotBreak, // GB6
+ (GC_LV, GC_V) => NotBreak, // GB7
+ (GC_LV, GC_T) => NotBreak, // GB7
+ (GC_V, GC_V) => NotBreak, // GB7
+ (GC_V, GC_T) => NotBreak, // GB7
+ (GC_LVT, GC_T) => NotBreak, // GB8
+ (GC_T, GC_T) => NotBreak, // GB8
+ (_, GC_Extend) => NotBreak, // GB9
+ (_, GC_ZWJ) => NotBreak, // GB9
+ (_, GC_SpacingMark) => Extended, // GB9a
+ (GC_Prepend, _) => Extended, // GB9b
+ (GC_ZWJ, GC_Extended_Pictographic) => Emoji, // GB11
+ (GC_Regional_Indicator, GC_Regional_Indicator) => Regional, // GB12, GB13
+ (_, _) => Break, // GB999
+ }
+}
+
+impl GraphemeCursor {
+ /// Create a new cursor. The string and initial offset are given at creation
+ /// time, but the contents of the string are not. The `is_extended` parameter
+ /// controls whether extended grapheme clusters are selected.
+ ///
+ /// The `offset` parameter must be on a codepoint boundary.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::GraphemeCursor;
+ /// let s = "हिन्दी";
+ /// let mut legacy = GraphemeCursor::new(0, s.len(), false);
+ /// assert_eq!(legacy.next_boundary(s, 0), Ok(Some("ह".len())));
+ /// let mut extended = GraphemeCursor::new(0, s.len(), true);
+ /// assert_eq!(extended.next_boundary(s, 0), Ok(Some("हि".len())));
+ /// ```
+ pub fn new(offset: usize, len: usize, is_extended: bool) -> GraphemeCursor {
+ let state = if offset == 0 || offset == len {
+ GraphemeState::Break
+ } else {
+ GraphemeState::Unknown
+ };
+ GraphemeCursor {
+ offset: offset,
+ len: len,
+ state: state,
+ is_extended: is_extended,
+ cat_before: None,
+ cat_after: None,
+ pre_context_offset: None,
+ ris_count: None,
+ resuming: false,
+ }
+ }
+
+ // Not sure I'm gonna keep this, the advantage over new() seems thin.
+
+ /// Set the cursor to a new location in the same string.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::GraphemeCursor;
+ /// let s = "abcd";
+ /// let mut cursor = GraphemeCursor::new(0, s.len(), false);
+ /// assert_eq!(cursor.cur_cursor(), 0);
+ /// cursor.set_cursor(2);
+ /// assert_eq!(cursor.cur_cursor(), 2);
+ /// ```
+ pub fn set_cursor(&mut self, offset: usize) {
+ if offset != self.offset {
+ self.offset = offset;
+ self.state = if offset == 0 || offset == self.len {
+ GraphemeState::Break
+ } else {
+ GraphemeState::Unknown
+ };
+ // reset state derived from text around cursor
+ self.cat_before = None;
+ self.cat_after = None;
+ self.ris_count = None;
+ }
+ }
+
+ #[inline]
+ /// The current offset of the cursor. Equal to the last value provided to
+ /// `new()` or `set_cursor()`, or returned from `next_boundary()` or
+ /// `prev_boundary()`.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::GraphemeCursor;
+ /// // Two flags (🇷🇸🇮🇴), each flag is two RIS codepoints, each RIS is 4 bytes.
+ /// let flags = "\u{1F1F7}\u{1F1F8}\u{1F1EE}\u{1F1F4}";
+ /// let mut cursor = GraphemeCursor::new(4, flags.len(), false);
+ /// assert_eq!(cursor.cur_cursor(), 4);
+ /// assert_eq!(cursor.next_boundary(flags, 0), Ok(Some(8)));
+ /// assert_eq!(cursor.cur_cursor(), 8);
+ /// ```
+ pub fn cur_cursor(&self) -> usize {
+ self.offset
+ }
+
+ /// Provide additional pre-context when it is needed to decide a boundary.
+ /// The end of the chunk must coincide with the value given in the
+ /// `GraphemeIncomplete::PreContext` request.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
+ /// let flags = "\u{1F1F7}\u{1F1F8}\u{1F1EE}\u{1F1F4}";
+ /// let mut cursor = GraphemeCursor::new(8, flags.len(), false);
+ /// // Not enough pre-context to decide if there's a boundary between the two flags.
+ /// assert_eq!(cursor.is_boundary(&flags[8..], 8), Err(GraphemeIncomplete::PreContext(8)));
+ /// // Provide one more Regional Indicator Symbol of pre-context
+ /// cursor.provide_context(&flags[4..8], 4);
+ /// // Still not enough context to decide.
+ /// assert_eq!(cursor.is_boundary(&flags[8..], 8), Err(GraphemeIncomplete::PreContext(4)));
+ /// // Provide additional requested context.
+ /// cursor.provide_context(&flags[0..4], 0);
+ /// // That's enough to decide (it always is when context goes to the start of the string)
+ /// assert_eq!(cursor.is_boundary(&flags[8..], 8), Ok(true));
+ /// ```
+ pub fn provide_context(&mut self, chunk: &str, chunk_start: usize) {
+ use tables::grapheme as gr;
+ assert!(chunk_start + chunk.len() == self.pre_context_offset.unwrap());
+ self.pre_context_offset = None;
+ if self.is_extended && chunk_start + chunk.len() == self.offset {
+ let ch = chunk.chars().rev().next().unwrap();
+ if gr::grapheme_category(ch) == gr::GC_Prepend {
+ self.decide(false); // GB9b
+ return;
+ }
+ }
+ match self.state {
+ GraphemeState::Regional => self.handle_regional(chunk, chunk_start),
+ GraphemeState::Emoji => self.handle_emoji(chunk, chunk_start),
+ _ => if self.cat_before.is_none() && self.offset == chunk.len() + chunk_start {
+ let ch = chunk.chars().rev().next().unwrap();
+ self.cat_before = Some(gr::grapheme_category(ch));
+ },
+ }
+ }
+
+ fn decide(&mut self, is_break: bool) {
+ self.state = if is_break {
+ GraphemeState::Break
+ } else {
+ GraphemeState::NotBreak
+ };
+ }
+
+ fn decision(&mut self, is_break: bool) -> Result<bool, GraphemeIncomplete> {
+ self.decide(is_break);
+ Ok(is_break)
+ }
+
+ fn is_boundary_result(&self) -> Result<bool, GraphemeIncomplete> {
+ if self.state == GraphemeState::Break {
+ Ok(true)
+ } else if self.state == GraphemeState::NotBreak {
+ Ok(false)
+ } else if let Some(pre_context_offset) = self.pre_context_offset {
+ Err(GraphemeIncomplete::PreContext(pre_context_offset))
+ } else {
+ unreachable!("inconsistent state");
+ }
+ }
+
+ fn handle_regional(&mut self, chunk: &str, chunk_start: usize) {
+ use tables::grapheme as gr;
+ let mut ris_count = self.ris_count.unwrap_or(0);
+ for ch in chunk.chars().rev() {
+ if gr::grapheme_category(ch) != gr::GC_Regional_Indicator {
+ self.ris_count = Some(ris_count);
+ self.decide((ris_count % 2) == 0);
+ return;
+ }
+ ris_count += 1;
+ }
+ self.ris_count = Some(ris_count);
+ if chunk_start == 0 {
+ self.decide((ris_count % 2) == 0);
+ return;
+ }
+ self.pre_context_offset = Some(chunk_start);
+ self.state = GraphemeState::Regional;
+ }
+
+ fn handle_emoji(&mut self, chunk: &str, chunk_start: usize) {
+ use tables::grapheme as gr;
+ let mut iter = chunk.chars().rev();
+ if let Some(ch) = iter.next() {
+ if gr::grapheme_category(ch) != gr::GC_ZWJ {
+ self.decide(true);
+ return;
+ }
+ }
+ for ch in iter {
+ match gr::grapheme_category(ch) {
+ gr::GC_Extend => (),
+ gr::GC_Extended_Pictographic => {
+ self.decide(false);
+ return;
+ }
+ _ => {
+ self.decide(true);
+ return;
+ }
+ }
+ }
+ if chunk_start == 0 {
+ self.decide(true);
+ return;
+ }
+ self.pre_context_offset = Some(chunk_start);
+ self.state = GraphemeState::Emoji;
+ }
+
+ /// Determine whether the current cursor location is a grapheme cluster boundary.
+ /// Only a part of the string need be supplied. If `chunk_start` is nonzero or
+ /// the length of `chunk` is not equal to `len` on creation, then this method
+ /// may return `GraphemeIncomplete::PreContext`. The caller should then
+ /// call `provide_context` with the requested chunk, then retry calling this
+ /// method.
+ ///
+ /// For partial chunks, if the cursor is not at the beginning or end of the
+ /// string, the chunk should contain at least the codepoint following the cursor.
+ /// If the string is nonempty, the chunk must be nonempty.
+ ///
+ /// All calls should have consistent chunk contents (ie, if a chunk provides
+ /// content for a given slice, all further chunks covering that slice must have
+ /// the same content for it).
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::GraphemeCursor;
+ /// let flags = "\u{1F1F7}\u{1F1F8}\u{1F1EE}\u{1F1F4}";
+ /// let mut cursor = GraphemeCursor::new(8, flags.len(), false);
+ /// assert_eq!(cursor.is_boundary(flags, 0), Ok(true));
+ /// cursor.set_cursor(12);
+ /// assert_eq!(cursor.is_boundary(flags, 0), Ok(false));
+ /// ```
+ pub fn is_boundary(&mut self, chunk: &str, chunk_start: usize) -> Result<bool, GraphemeIncomplete> {
+ use tables::grapheme as gr;
+ if self.state == GraphemeState::Break {
+ return Ok(true)
+ }
+ if self.state == GraphemeState::NotBreak {
+ return Ok(false)
+ }
+ if self.offset < chunk_start || self.offset >= chunk_start + chunk.len() {
+ if self.offset > chunk_start + chunk.len() || self.cat_after.is_none() {
+ return Err(GraphemeIncomplete::InvalidOffset)
+ }
+ }
+ if let Some(pre_context_offset) = self.pre_context_offset {
+ return Err(GraphemeIncomplete::PreContext(pre_context_offset));
+ }
+ let offset_in_chunk = self.offset - chunk_start;
+ if self.cat_after.is_none() {
+ let ch = chunk[offset_in_chunk..].chars().next().unwrap();
+ self.cat_after = Some(gr::grapheme_category(ch));
+ }
+ if self.offset == chunk_start {
+ let mut need_pre_context = true;
+ match self.cat_after.unwrap() {
+ gr::GC_Regional_Indicator => self.state = GraphemeState::Regional,
+ gr::GC_Extended_Pictographic => self.state = GraphemeState::Emoji,
+ _ => need_pre_context = self.cat_before.is_none(),
+ }
+ if need_pre_context {
+ self.pre_context_offset = Some(chunk_start);
+ return Err(GraphemeIncomplete::PreContext(chunk_start));
+ }
+ }
+ if self.cat_before.is_none() {
+ let ch = chunk[..offset_in_chunk].chars().rev().next().unwrap();
+ self.cat_before = Some(gr::grapheme_category(ch));
+ }
+ match check_pair(self.cat_before.unwrap(), self.cat_after.unwrap()) {
+ PairResult::NotBreak => return self.decision(false),
+ PairResult::Break => return self.decision(true),
+ PairResult::Extended => {
+ let is_extended = self.is_extended;
+ return self.decision(!is_extended);
+ }
+ PairResult::Regional => {
+ if let Some(ris_count) = self.ris_count {
+ return self.decision((ris_count % 2) == 0);
+ }
+ self.handle_regional(&chunk[..offset_in_chunk], chunk_start);
+ self.is_boundary_result()
+ }
+ PairResult::Emoji => {
+ self.handle_emoji(&chunk[..offset_in_chunk], chunk_start);
+ self.is_boundary_result()
+ }
+ }
+ }
+
+ /// Find the next boundary after the current cursor position. Only a part of
+ /// the string need be supplied. If the chunk is incomplete, then this
+ /// method might return `GraphemeIncomplete::PreContext` or
+ /// `GraphemeIncomplete::NextChunk`. In the former case, the caller should
+ /// call `provide_context` with the requested chunk, then retry. In the
+ /// latter case, the caller should provide the chunk following the one
+ /// given, then retry.
+ ///
+ /// See `is_boundary` for expectations on the provided chunk.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::GraphemeCursor;
+ /// let flags = "\u{1F1F7}\u{1F1F8}\u{1F1EE}\u{1F1F4}";
+ /// let mut cursor = GraphemeCursor::new(4, flags.len(), false);
+ /// assert_eq!(cursor.next_boundary(flags, 0), Ok(Some(8)));
+ /// assert_eq!(cursor.next_boundary(flags, 0), Ok(Some(16)));
+ /// assert_eq!(cursor.next_boundary(flags, 0), Ok(None));
+ /// ```
+ ///
+ /// And an example that uses partial strings:
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
+ /// let s = "abcd";
+ /// let mut cursor = GraphemeCursor::new(0, s.len(), false);
+ /// assert_eq!(cursor.next_boundary(&s[..2], 0), Ok(Some(1)));
+ /// assert_eq!(cursor.next_boundary(&s[..2], 0), Err(GraphemeIncomplete::NextChunk));
+ /// assert_eq!(cursor.next_boundary(&s[2..4], 2), Ok(Some(2)));
+ /// assert_eq!(cursor.next_boundary(&s[2..4], 2), Ok(Some(3)));
+ /// assert_eq!(cursor.next_boundary(&s[2..4], 2), Ok(Some(4)));
+ /// assert_eq!(cursor.next_boundary(&s[2..4], 2), Ok(None));
+ /// ```
+ pub fn next_boundary(&mut self, chunk: &str, chunk_start: usize) -> Result<Option<usize>, GraphemeIncomplete> {
+ use tables::grapheme as gr;
+ if self.offset == self.len {
+ return Ok(None);
+ }
+ let mut iter = chunk[self.offset - chunk_start..].chars();
+ let mut ch = iter.next().unwrap();
+ loop {
+ if self.resuming {
+ if self.cat_after.is_none() {
+ self.cat_after = Some(gr::grapheme_category(ch));
+ }
+ } else {
+ self.offset += ch.len_utf8();
+ self.state = GraphemeState::Unknown;
+ self.cat_before = self.cat_after.take();
+ if self.cat_before.is_none() {
+ self.cat_before = Some(gr::grapheme_category(ch));
+ }
+ if self.cat_before.unwrap() == GraphemeCat::GC_Regional_Indicator {
+ self.ris_count = self.ris_count.map(|c| c + 1);
+ } else {
+ self.ris_count = Some(0);
+ }
+ if let Some(next_ch) = iter.next() {
+ ch = next_ch;
+ self.cat_after = Some(gr::grapheme_category(ch));
+ } else if self.offset == self.len {
+ self.decide(true);
+ } else {
+ self.resuming = true;
+ return Err(GraphemeIncomplete::NextChunk);
+ }
+ }
+ self.resuming = true;
+ if self.is_boundary(chunk, chunk_start)? {
+ self.resuming = false;
+ return Ok(Some(self.offset));
+ }
+ self.resuming = false;
+ }
+ }
+
+ /// Find the previous boundary after the current cursor position. Only a part
+ /// of the string need be supplied. If the chunk is incomplete, then this
+ /// method might return `GraphemeIncomplete::PreContext` or
+ /// `GraphemeIncomplete::PrevChunk`. In the former case, the caller should
+ /// call `provide_context` with the requested chunk, then retry. In the
+ /// latter case, the caller should provide the chunk preceding the one
+ /// given, then retry.
+ ///
+ /// See `is_boundary` for expectations on the provided chunk.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::GraphemeCursor;
+ /// let flags = "\u{1F1F7}\u{1F1F8}\u{1F1EE}\u{1F1F4}";
+ /// let mut cursor = GraphemeCursor::new(12, flags.len(), false);
+ /// assert_eq!(cursor.prev_boundary(flags, 0), Ok(Some(8)));
+ /// assert_eq!(cursor.prev_boundary(flags, 0), Ok(Some(0)));
+ /// assert_eq!(cursor.prev_boundary(flags, 0), Ok(None));
+ /// ```
+ ///
+ /// And an example that uses partial strings (note the exact return is not
+ /// guaranteed, and may be `PrevChunk` or `PreContext` arbitrarily):
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
+ /// let s = "abcd";
+ /// let mut cursor = GraphemeCursor::new(4, s.len(), false);
+ /// assert_eq!(cursor.prev_boundary(&s[2..4], 2), Ok(Some(3)));
+ /// assert_eq!(cursor.prev_boundary(&s[2..4], 2), Err(GraphemeIncomplete::PrevChunk));
+ /// assert_eq!(cursor.prev_boundary(&s[0..2], 0), Ok(Some(2)));
+ /// assert_eq!(cursor.prev_boundary(&s[0..2], 0), Ok(Some(1)));
+ /// assert_eq!(cursor.prev_boundary(&s[0..2], 0), Ok(Some(0)));
+ /// assert_eq!(cursor.prev_boundary(&s[0..2], 0), Ok(None));
+ /// ```
+ pub fn prev_boundary(&mut self, chunk: &str, chunk_start: usize) -> Result<Option<usize>, GraphemeIncomplete> {
+ use tables::grapheme as gr;
+ if self.offset == 0 {
+ return Ok(None);
+ }
+ if self.offset == chunk_start {
+ return Err(GraphemeIncomplete::PrevChunk);
+ }
+ let mut iter = chunk[..self.offset - chunk_start].chars().rev();
+ let mut ch = iter.next().unwrap();
+ loop {
+ if self.offset == chunk_start {
+ self.resuming = true;
+ return Err(GraphemeIncomplete::PrevChunk);
+ }
+ if self.resuming {
+ self.cat_before = Some(gr::grapheme_category(ch));
+ } else {
+ self.offset -= ch.len_utf8();
+ self.cat_after = self.cat_before.take();
+ self.state = GraphemeState::Unknown;
+ if let Some(ris_count) = self.ris_count {
+ self.ris_count = if ris_count > 0 { Some(ris_count - 1) } else { None };
+ }
+ if let Some(prev_ch) = iter.next() {
+ ch = prev_ch;
+ self.cat_before = Some(gr::grapheme_category(ch));
+ } else if self.offset == 0 {
+ self.decide(true);
+ } else {
+ self.resuming = true;
+ self.cat_after = Some(gr::grapheme_category(ch));
+ return Err(GraphemeIncomplete::PrevChunk);
+ }
+ }
+ self.resuming = true;
+ if self.is_boundary(chunk, chunk_start)? {
+ self.resuming = false;
+ return Ok(Some(self.offset));
+ }
+ self.resuming = false;
+ }
+ }
+}
+
+#[test]
+fn test_grapheme_cursor_ris_precontext() {
+ let s = "\u{1f1fa}\u{1f1f8}\u{1f1fa}\u{1f1f8}\u{1f1fa}\u{1f1f8}";
+ let mut c = GraphemeCursor::new(8, s.len(), true);
+ assert_eq!(c.is_boundary(&s[4..], 4), Err(GraphemeIncomplete::PreContext(4)));
+ c.provide_context(&s[..4], 0);
+ assert_eq!(c.is_boundary(&s[4..], 4), Ok(true));
+}
+
+#[test]
+fn test_grapheme_cursor_chunk_start_require_precontext() {
+ let s = "\r\n";
+ let mut c = GraphemeCursor::new(1, s.len(), true);
+ assert_eq!(c.is_boundary(&s[1..], 1), Err(GraphemeIncomplete::PreContext(1)));
+ c.provide_context(&s[..1], 0);
+ assert_eq!(c.is_boundary(&s[1..], 1), Ok(false));
+}
+
+#[test]
+fn test_grapheme_cursor_prev_boundary() {
+ let s = "abcd";
+ let mut c = GraphemeCursor::new(3, s.len(), true);
+ assert_eq!(c.prev_boundary(&s[2..], 2), Err(GraphemeIncomplete::PrevChunk));
+ assert_eq!(c.prev_boundary(&s[..2], 0), Ok(Some(2)));
+}
+
+#[test]
+fn test_grapheme_cursor_prev_boundary_chunk_start() {
+ let s = "abcd";
+ let mut c = GraphemeCursor::new(2, s.len(), true);
+ assert_eq!(c.prev_boundary(&s[2..], 2), Err(GraphemeIncomplete::PrevChunk));
+ assert_eq!(c.prev_boundary(&s[..2], 0), Ok(Some(1)));
+}
diff --git a/unicode-segmentation/src/lib.rs b/unicode-segmentation/src/lib.rs
new file mode 100644
index 0000000..fce3c52
--- /dev/null
+++ b/unicode-segmentation/src/lib.rs
@@ -0,0 +1,242 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Iterators which split strings on Grapheme Cluster, Word or Sentence boundaries, according
+//! to the [Unicode Standard Annex #29](http://www.unicode.org/reports/tr29/) rules.
+//!
+//! ```rust
+//! extern crate unicode_segmentation;
+//!
+//! use unicode_segmentation::UnicodeSegmentation;
+//!
+//! fn main() {
+//! let s = "a̐éö̲\r\n";
+//! let g = UnicodeSegmentation::graphemes(s, true).collect::<Vec<&str>>();
+//! let b: &[_] = &["a̐", "é", "ö̲", "\r\n"];
+//! assert_eq!(g, b);
+//!
+//! let s = "The quick (\"brown\") fox can't jump 32.3 feet, right?";
+//! let w = s.unicode_words().collect::<Vec<&str>>();
+//! let b: &[_] = &["The", "quick", "brown", "fox", "can't", "jump", "32.3", "feet", "right"];
+//! assert_eq!(w, b);
+//!
+//! let s = "The quick (\"brown\") fox";
+//! let w = s.split_word_bounds().collect::<Vec<&str>>();
+//! let b: &[_] = &["The", " ", "quick", " ", "(", "\"", "brown", "\"", ")", " ", "fox"];
+//! assert_eq!(w, b);
+//! }
+//! ```
+//!
+//! # no_std
+//!
+//! unicode-segmentation does not depend on libstd, so it can be used in crates
+//! with the `#![no_std]` attribute.
+//!
+//! # crates.io
+//!
+//! You can use this package in your project by adding the following
+//! to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! unicode-segmentation = "1.3.0"
+//! ```
+
+#![deny(missing_docs, unsafe_code)]
+#![doc(html_logo_url = "https://unicode-rs.github.io/unicode-rs_sm.png",
+ html_favicon_url = "https://unicode-rs.github.io/unicode-rs_sm.png")]
+
+#![no_std]
+
+#[cfg(test)]
+#[macro_use]
+extern crate std;
+
+#[cfg(test)]
+#[macro_use]
+extern crate quickcheck;
+
+pub use grapheme::{Graphemes, GraphemeIndices};
+pub use grapheme::{GraphemeCursor, GraphemeIncomplete};
+pub use tables::UNICODE_VERSION;
+pub use word::{UWordBounds, UWordBoundIndices, UnicodeWords};
+pub use sentence::{USentenceBounds, USentenceBoundIndices, UnicodeSentences};
+
+mod grapheme;
+mod tables;
+mod word;
+mod sentence;
+
+#[cfg(test)]
+mod test;
+#[cfg(test)]
+mod testdata;
+
+/// Methods for segmenting strings according to
+/// [Unicode Standard Annex #29](http://www.unicode.org/reports/tr29/).
+pub trait UnicodeSegmentation {
+ /// Returns an iterator over the [grapheme clusters][graphemes] of `self`.
+ ///
+ /// [graphemes]: http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
+ ///
+ /// If `is_extended` is true, the iterator is over the
+ /// *extended grapheme clusters*;
+ /// otherwise, the iterator is over the *legacy grapheme clusters*.
+ /// [UAX#29](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)
+ /// recommends extended grapheme cluster boundaries for general processing.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use self::unicode_segmentation::UnicodeSegmentation;
+ /// let gr1 = UnicodeSegmentation::graphemes("a\u{310}e\u{301}o\u{308}\u{332}", true)
+ /// .collect::<Vec<&str>>();
+ /// let b: &[_] = &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"];
+ ///
+ /// assert_eq!(&gr1[..], b);
+ ///
+ /// let gr2 = UnicodeSegmentation::graphemes("a\r\nb🇷🇺🇸🇹", true).collect::<Vec<&str>>();
+ /// let b: &[_] = &["a", "\r\n", "b", "🇷🇺", "🇸🇹"];
+ ///
+ /// assert_eq!(&gr2[..], b);
+ /// ```
+ fn graphemes<'a>(&'a self, is_extended: bool) -> Graphemes<'a>;
+
+ /// Returns an iterator over the grapheme clusters of `self` and their
+ /// byte offsets. See `graphemes()` for more information.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use self::unicode_segmentation::UnicodeSegmentation;
+ /// let gr_inds = UnicodeSegmentation::grapheme_indices("a̐éö̲\r\n", true)
+ /// .collect::<Vec<(usize, &str)>>();
+ /// let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")];
+ ///
+ /// assert_eq!(&gr_inds[..], b);
+ /// ```
+ fn grapheme_indices<'a>(&'a self, is_extended: bool) -> GraphemeIndices<'a>;
+
+ /// Returns an iterator over the words of `self`, separated on
+ /// [UAX#29 word boundaries](http://www.unicode.org/reports/tr29/#Word_Boundaries).
+ ///
+ /// Here, "words" are just those substrings which, after splitting on
+ /// UAX#29 word boundaries, contain any alphanumeric characters. That is, the
+ /// substring must contain at least one character with the
+ /// [Alphabetic](http://unicode.org/reports/tr44/#Alphabetic)
+ /// property, or with
+ /// [General_Category=Number](http://unicode.org/reports/tr44/#General_Category_Values).
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use self::unicode_segmentation::UnicodeSegmentation;
+ /// let uws = "The quick (\"brown\") fox can't jump 32.3 feet, right?";
+ /// let uw1 = uws.unicode_words().collect::<Vec<&str>>();
+ /// let b: &[_] = &["The", "quick", "brown", "fox", "can't", "jump", "32.3", "feet", "right"];
+ ///
+ /// assert_eq!(&uw1[..], b);
+ /// ```
+ fn unicode_words<'a>(&'a self) -> UnicodeWords<'a>;
+
+ /// Returns an iterator over substrings of `self` separated on
+ /// [UAX#29 word boundaries](http://www.unicode.org/reports/tr29/#Word_Boundaries).
+ ///
+ /// The concatenation of the substrings returned by this function is just the original string.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use self::unicode_segmentation::UnicodeSegmentation;
+ /// let swu1 = "The quick (\"brown\") fox".split_word_bounds().collect::<Vec<&str>>();
+ /// let b: &[_] = &["The", " ", "quick", " ", "(", "\"", "brown", "\"", ")", " ", "fox"];
+ ///
+ /// assert_eq!(&swu1[..], b);
+ /// ```
+ fn split_word_bounds<'a>(&'a self) -> UWordBounds<'a>;
+
+ /// Returns an iterator over substrings of `self`, split on UAX#29 word boundaries,
+ /// and their offsets. See `split_word_bounds()` for more information.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use self::unicode_segmentation::UnicodeSegmentation;
+ /// let swi1 = "Brr, it's 29.3°F!".split_word_bound_indices().collect::<Vec<(usize, &str)>>();
+ /// let b: &[_] = &[(0, "Brr"), (3, ","), (4, " "), (5, "it's"), (9, " "), (10, "29.3"),
+ /// (14, "°"), (16, "F"), (17, "!")];
+ ///
+ /// assert_eq!(&swi1[..], b);
+ /// ```
+ fn split_word_bound_indices<'a>(&'a self) -> UWordBoundIndices<'a>;
+
+ /// Returns an iterator over substrings of `self` separated on
+ /// [UAX#29 sentence boundaries](http://www.unicode.org/reports/tr29/#Sentence_Boundaries).
+ ///
+ /// The concatenation of the substrings returned by this function is just the original string.
+ fn unicode_sentences<'a>(&'a self) -> UnicodeSentences<'a>;
+
+ /// Returns an iterator over substrings of `self` separated on
+ /// [UAX#29 sentence boundaries](http://www.unicode.org/reports/tr29/#Sentence_Boundaries).
+ ///
+ /// Here, "sentences" are just those substrings which, after splitting on
+ /// UAX#29 sentence boundaries, contain any alphanumeric characters. That is, the
+ /// substring must contain at least one character with the
+ /// [Alphabetic](http://unicode.org/reports/tr44/#Alphabetic)
+ /// property, or with
+ /// [General_Category=Number](http://unicode.org/reports/tr44/#General_Category_Values).
+ fn split_sentence_bounds<'a>(&'a self) -> USentenceBounds<'a>;
+
+ /// Returns an iterator over substrings of `self`, split on UAX#29 sentence boundaries,
+ /// and their offsets. See `split_sentence_bounds()` for more information.
+ fn split_sentence_bound_indices<'a>(&'a self) -> USentenceBoundIndices<'a>;
+}
+
+impl UnicodeSegmentation for str {
+ #[inline]
+ fn graphemes(&self, is_extended: bool) -> Graphemes {
+ grapheme::new_graphemes(self, is_extended)
+ }
+
+ #[inline]
+ fn grapheme_indices(&self, is_extended: bool) -> GraphemeIndices {
+ grapheme::new_grapheme_indices(self, is_extended)
+ }
+
+ #[inline]
+ fn unicode_words(&self) -> UnicodeWords {
+ word::new_unicode_words(self)
+ }
+
+ #[inline]
+ fn split_word_bounds(&self) -> UWordBounds {
+ word::new_word_bounds(self)
+ }
+
+ #[inline]
+ fn split_word_bound_indices(&self) -> UWordBoundIndices {
+ word::new_word_bound_indices(self)
+ }
+
+ #[inline]
+ fn unicode_sentences(&self) -> UnicodeSentences {
+ sentence::new_unicode_sentences(self)
+ }
+
+ #[inline]
+ fn split_sentence_bounds(&self) -> USentenceBounds {
+ sentence::new_sentence_bounds(self)
+ }
+
+ #[inline]
+ fn split_sentence_bound_indices(&self) -> USentenceBoundIndices {
+ sentence::new_sentence_bound_indices(self)
+ }
+}
diff --git a/unicode-segmentation/src/sentence.rs b/unicode-segmentation/src/sentence.rs
new file mode 100644
index 0000000..c16c927
--- /dev/null
+++ b/unicode-segmentation/src/sentence.rs
@@ -0,0 +1,373 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::cmp;
+use core::iter::Filter;
+
+// All of the logic for forward iteration over sentences
+mod fwd {
+ use tables::sentence::SentenceCat;
+ use core::cmp;
+
+ // Describe a parsed part of source string as described in this table:
+ // https://unicode.org/reports/tr29/#Default_Sentence_Boundaries
+ #[derive(Clone, Copy, PartialEq, Eq)]
+ enum StatePart {
+ Sot,
+ Eot,
+ Other,
+ CR,
+ LF,
+ Sep,
+ ATerm,
+ UpperLower,
+ ClosePlus,
+ SpPlus,
+ STerm
+ }
+
+ #[derive(Clone, PartialEq, Eq)]
+ struct SentenceBreaksState(pub [StatePart; 4]);
+
+ const INITIAL_STATE: SentenceBreaksState = SentenceBreaksState([
+ StatePart::Sot,
+ StatePart::Sot,
+ StatePart::Sot,
+ StatePart::Sot
+ ]);
+
+ #[derive(Clone)]
+ pub struct SentenceBreaks<'a> {
+ pub string: &'a str,
+ pos: usize,
+ state: SentenceBreaksState
+ }
+
+ impl SentenceBreaksState {
+ // Attempt to advance the internal state by one part
+ // Whitespace and some punctutation will be collapsed
+ fn next(&self, cat: SentenceCat) -> SentenceBreaksState {
+ let &SentenceBreaksState(parts) = self;
+ let parts = match (parts[3], cat) {
+ (StatePart::ClosePlus, SentenceCat::SC_Close) => parts,
+ (StatePart::SpPlus, SentenceCat::SC_Sp) => parts,
+ _ => [
+ parts[1],
+ parts[2],
+ parts[3],
+ match cat {
+ SentenceCat::SC_CR => StatePart::CR,
+ SentenceCat::SC_LF => StatePart::LF,
+ SentenceCat::SC_Sep => StatePart::Sep,
+ SentenceCat::SC_ATerm => StatePart::ATerm,
+ SentenceCat::SC_Upper |
+ SentenceCat::SC_Lower => StatePart::UpperLower,
+ SentenceCat::SC_Close => StatePart::ClosePlus,
+ SentenceCat::SC_Sp => StatePart::SpPlus,
+ SentenceCat::SC_STerm => StatePart::STerm,
+ _ => StatePart::Other
+ }
+ ]
+ };
+ SentenceBreaksState(parts)
+ }
+
+ fn end(&self) -> SentenceBreaksState {
+ let &SentenceBreaksState(parts) = self;
+ SentenceBreaksState([
+ parts[1],
+ parts[2],
+ parts[3],
+ StatePart::Eot
+ ])
+ }
+
+ // Helper function to check if state head matches a single `StatePart`
+ fn match1(&self, part: StatePart) -> bool {
+ let &SentenceBreaksState(parts) = self;
+ part == parts[3]
+ }
+
+ // Helper function to check if first two `StateParts` in state match
+ // the given two
+ fn match2(&self, part1: StatePart, part2: StatePart) -> bool {
+ let &SentenceBreaksState(parts) = self;
+ part1 == parts[2] && part2 == parts[3]
+ }
+ }
+
+ // https://unicode.org/reports/tr29/#SB8
+ // TODO cache this, it is currently quadratic
+ fn match_sb8(state: &SentenceBreaksState, ahead: &str) -> bool {
+ let &SentenceBreaksState(parts) = state;
+ let mut idx = if parts[3] == StatePart::SpPlus { 2 } else { 3 };
+ if parts[idx] == StatePart::ClosePlus { idx -= 1 }
+
+ if parts[idx] == StatePart::ATerm {
+ use tables::sentence as se;
+
+ for next_char in ahead.chars() {
+ //( ¬(OLetter | Upper | Lower | ParaSep | SATerm) )* Lower
+ match se::sentence_category(next_char) {
+ se::SC_Lower => return true,
+ se::SC_OLetter |
+ se::SC_Upper |
+ se::SC_Sep | se::SC_CR | se::SC_LF |
+ se::SC_STerm | se::SC_ATerm => return false,
+ _ => continue
+ }
+ }
+ }
+
+ false
+ }
+
+ // https://unicode.org/reports/tr29/#SB8a
+ fn match_sb8a(state: &SentenceBreaksState) -> bool {
+ // SATerm Close* Sp*
+ let &SentenceBreaksState(parts) = state;
+ let mut idx = if parts[3] == StatePart::SpPlus { 2 } else { 3 };
+ if parts[idx] == StatePart::ClosePlus { idx -= 1 }
+ parts[idx] == StatePart::STerm || parts[idx] == StatePart::ATerm
+ }
+
+ // https://unicode.org/reports/tr29/#SB9
+ fn match_sb9(state: &SentenceBreaksState) -> bool {
+ // SATerm Close*
+ let &SentenceBreaksState(parts) = state;
+ let idx = if parts[3] == StatePart::ClosePlus { 2 } else { 3 };
+ parts[idx] == StatePart::STerm || parts[idx] == StatePart::ATerm
+ }
+
+ // https://unicode.org/reports/tr29/#SB11
+ fn match_sb11(state: &SentenceBreaksState) -> bool {
+ // SATerm Close* Sp* ParaSep?
+ let &SentenceBreaksState(parts) = state;
+ let mut idx = match parts[3] {
+ StatePart::Sep |
+ StatePart::CR |
+ StatePart::LF => 2,
+ _ => 3
+ };
+
+ if parts[idx] == StatePart::SpPlus { idx -= 1 }
+ if parts[idx] == StatePart::ClosePlus { idx -= 1}
+
+ parts[idx] == StatePart::STerm || parts[idx] == StatePart::ATerm
+ }
+
+ impl<'a> Iterator for SentenceBreaks<'a> {
+ // Returns the index of the character which follows a break
+ type Item = usize;
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let slen = self.string.len();
+ // A sentence could be one character
+ (cmp::min(slen, 2), Some(slen + 1))
+ }
+
+ #[inline]
+ fn next(&mut self) -> Option<usize> {
+ use tables::sentence as se;
+
+ for next_char in self.string[self.pos..].chars() {
+ let position_before = self.pos;
+ let state_before = self.state.clone();
+
+ let next_cat = se::sentence_category(next_char);
+
+ self.pos += next_char.len_utf8();
+ self.state = self.state.next(next_cat);
+
+ match next_cat {
+ // SB1 https://unicode.org/reports/tr29/#SB1
+ _ if state_before.match1(StatePart::Sot) =>
+ return Some(position_before),
+
+ // SB2 is handled when inner iterator (chars) is finished
+
+ // SB3 https://unicode.org/reports/tr29/#SB3
+ SentenceCat::SC_LF if state_before.match1(StatePart::CR) =>
+ continue,
+
+ // SB4 https://unicode.org/reports/tr29/#SB4
+ _ if state_before.match1(StatePart::Sep)
+ || state_before.match1(StatePart::CR)
+ || state_before.match1(StatePart::LF)
+ => return Some(position_before),
+
+ // SB5 https://unicode.org/reports/tr29/#SB5
+ SentenceCat::SC_Extend |
+ SentenceCat::SC_Format => self.state = state_before,
+
+ // SB6 https://unicode.org/reports/tr29/#SB6
+ SentenceCat::SC_Numeric if state_before.match1(StatePart::ATerm) =>
+ continue,
+
+ // SB7 https://unicode.org/reports/tr29/#SB7
+ SentenceCat::SC_Upper if state_before.match2(StatePart::UpperLower, StatePart::ATerm) =>
+ continue,
+
+ // SB8 https://unicode.org/reports/tr29/#SB8
+ _ if match_sb8(&state_before, &self.string[position_before..]) =>
+ continue,
+
+ // SB8a https://unicode.org/reports/tr29/#SB8a
+ SentenceCat::SC_SContinue |
+ SentenceCat::SC_STerm |
+ SentenceCat::SC_ATerm if match_sb8a(&state_before) =>
+ continue,
+
+ // SB9 https://unicode.org/reports/tr29/#SB9
+ SentenceCat::SC_Close |
+ SentenceCat::SC_Sp |
+ SentenceCat::SC_Sep |
+ SentenceCat::SC_CR |
+ SentenceCat::SC_LF if match_sb9(&state_before) =>
+ continue,
+
+ // SB10 https://unicode.org/reports/tr29/#SB10
+ SentenceCat::SC_Sp |
+ SentenceCat::SC_Sep |
+ SentenceCat::SC_CR |
+ SentenceCat::SC_LF if match_sb8a(&state_before) =>
+ continue,
+
+ // SB11 https://unicode.org/reports/tr29/#SB11
+ _ if match_sb11(&state_before) =>
+ return Some(position_before),
+
+ // SB998 https://unicode.org/reports/tr29/#SB998
+ _ => continue
+ }
+ }
+
+ // SB2 https://unicode.org/reports/tr29/#SB2
+ if self.state.match1(StatePart::Sot) {
+ None
+ } else if self.state.match1(StatePart::Eot) {
+ None
+ } else {
+ self.state = self.state.end();
+ Some(self.pos)
+ }
+ }
+ }
+
+ pub fn new_sentence_breaks<'a>(source: &'a str) -> SentenceBreaks<'a> {
+ SentenceBreaks { string: source, pos: 0, state: INITIAL_STATE }
+ }
+
+}
+
+/// An iterator over the substrings of a string which, after splitting the string on
+/// [sentence boundaries](http://www.unicode.org/reports/tr29/#Sentence_Boundaries),
+/// contain any characters with the
+/// [Alphabetic](http://unicode.org/reports/tr44/#Alphabetic)
+/// property, or with
+/// [General_Category=Number](http://unicode.org/reports/tr44/#General_Category_Values).
+#[derive(Clone)]
+pub struct UnicodeSentences<'a> {
+ inner: Filter<USentenceBounds<'a>, fn(&&str) -> bool>,
+}
+
+/// External iterator for a string's
+/// [sentence boundaries](http://www.unicode.org/reports/tr29/#Sentence_Boundaries).
+#[derive(Clone)]
+pub struct USentenceBounds<'a> {
+ iter: fwd::SentenceBreaks<'a>,
+ sentence_start: Option<usize>
+}
+
+/// External iterator for sentence boundaries and byte offsets.
+#[derive(Clone)]
+pub struct USentenceBoundIndices<'a> {
+ start_offset: usize,
+ iter: USentenceBounds<'a>,
+}
+
+#[inline]
+pub fn new_sentence_bounds<'a>(source: &'a str) -> USentenceBounds<'a> {
+ USentenceBounds {
+ iter: fwd::new_sentence_breaks(source),
+ sentence_start: None
+ }
+}
+
+#[inline]
+pub fn new_sentence_bound_indices<'a>(source: &'a str) -> USentenceBoundIndices<'a> {
+ USentenceBoundIndices {
+ start_offset: source.as_ptr() as usize,
+ iter: new_sentence_bounds(source)
+ }
+}
+
+#[inline]
+pub fn new_unicode_sentences<'b>(s: &'b str) -> UnicodeSentences<'b> {
+ use super::UnicodeSegmentation;
+ use tables::util::is_alphanumeric;
+
+ fn has_alphanumeric(s: &&str) -> bool { s.chars().any(|c| is_alphanumeric(c)) }
+ let has_alphanumeric: fn(&&str) -> bool = has_alphanumeric; // coerce to fn pointer
+
+ UnicodeSentences { inner: s.split_sentence_bounds().filter(has_alphanumeric) }
+}
+
+impl<'a> Iterator for UnicodeSentences<'a> {
+ type Item = &'a str;
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a str> { self.inner.next() }
+}
+
+impl<'a> Iterator for USentenceBounds<'a> {
+ type Item = &'a str;
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (lower, upper) = self.iter.size_hint();
+ (cmp::max(0, lower - 1), upper.map(|u| cmp::max(0, u - 1)))
+ }
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a str> {
+ if self.sentence_start == None {
+ if let Some(start_pos) = self.iter.next() {
+ self.sentence_start = Some(start_pos)
+ } else {
+ return None
+ }
+ }
+
+ if let Some(break_pos) = self.iter.next() {
+ let start_pos = self.sentence_start.unwrap();
+ let sentence = &self.iter.string[start_pos..break_pos];
+ self.sentence_start = Some(break_pos);
+ Some(sentence)
+ } else {
+ None
+ }
+ }
+}
+
+impl<'a> Iterator for USentenceBoundIndices<'a> {
+ type Item = (usize, &'a str);
+
+ #[inline]
+ fn next(&mut self) -> Option<(usize, &'a str)> {
+ self.iter.next().map(|s| (s.as_ptr() as usize - self.start_offset, s))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
diff --git a/unicode-segmentation/src/tables.rs b/unicode-segmentation/src/tables.rs
new file mode 100644
index 0000000..bfd7290
--- /dev/null
+++ b/unicode-segmentation/src/tables.rs
@@ -0,0 +1,2523 @@
+// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly
+
+#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
+
+/// The version of [Unicode](http://www.unicode.org/)
+/// that this version of unicode-segmentation is based on.
+pub const UNICODE_VERSION: (u64, u64, u64) = (12, 0, 0);
+
+pub mod util {
+ #[inline]
+ pub fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ r.binary_search_by(|&(lo,hi)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }).is_ok()
+ }
+
+ #[inline]
+ fn is_alphabetic(c: char) -> bool {
+ match c {
+ 'a' ... 'z' | 'A' ... 'Z' => true,
+ c if c > '' => super::derived_property::Alphabetic(c),
+ _ => false,
+ }
+ }
+
+ #[inline]
+ fn is_numeric(c: char) -> bool {
+ match c {
+ '0' ... '9' => true,
+ c if c > '' => super::general_category::N(c),
+ _ => false,
+ }
+ }
+
+ #[inline]
+ pub fn is_alphanumeric(c: char) -> bool {
+ is_alphabetic(c) || is_numeric(c)
+ }
+}
+
+mod general_category {
+ const N_table: &'static [(char, char)] = &[
+ ('\u{30}', '\u{39}'), ('\u{b2}', '\u{b3}'), ('\u{b9}', '\u{b9}'), ('\u{bc}', '\u{be}'),
+ ('\u{660}', '\u{669}'), ('\u{6f0}', '\u{6f9}'), ('\u{7c0}', '\u{7c9}'), ('\u{966}',
+ '\u{96f}'), ('\u{9e6}', '\u{9ef}'), ('\u{9f4}', '\u{9f9}'), ('\u{a66}', '\u{a6f}'),
+ ('\u{ae6}', '\u{aef}'), ('\u{b66}', '\u{b6f}'), ('\u{b72}', '\u{b77}'), ('\u{be6}',
+ '\u{bf2}'), ('\u{c66}', '\u{c6f}'), ('\u{c78}', '\u{c7e}'), ('\u{ce6}', '\u{cef}'),
+ ('\u{d58}', '\u{d5e}'), ('\u{d66}', '\u{d78}'), ('\u{de6}', '\u{def}'), ('\u{e50}',
+ '\u{e59}'), ('\u{ed0}', '\u{ed9}'), ('\u{f20}', '\u{f33}'), ('\u{1040}', '\u{1049}'),
+ ('\u{1090}', '\u{1099}'), ('\u{1369}', '\u{137c}'), ('\u{16ee}', '\u{16f0}'), ('\u{17e0}',
+ '\u{17e9}'), ('\u{17f0}', '\u{17f9}'), ('\u{1810}', '\u{1819}'), ('\u{1946}', '\u{194f}'),
+ ('\u{19d0}', '\u{19da}'), ('\u{1a80}', '\u{1a89}'), ('\u{1a90}', '\u{1a99}'), ('\u{1b50}',
+ '\u{1b59}'), ('\u{1bb0}', '\u{1bb9}'), ('\u{1c40}', '\u{1c49}'), ('\u{1c50}', '\u{1c59}'),
+ ('\u{2070}', '\u{2070}'), ('\u{2074}', '\u{2079}'), ('\u{2080}', '\u{2089}'), ('\u{2150}',
+ '\u{2182}'), ('\u{2185}', '\u{2189}'), ('\u{2460}', '\u{249b}'), ('\u{24ea}', '\u{24ff}'),
+ ('\u{2776}', '\u{2793}'), ('\u{2cfd}', '\u{2cfd}'), ('\u{3007}', '\u{3007}'), ('\u{3021}',
+ '\u{3029}'), ('\u{3038}', '\u{303a}'), ('\u{3192}', '\u{3195}'), ('\u{3220}', '\u{3229}'),
+ ('\u{3248}', '\u{324f}'), ('\u{3251}', '\u{325f}'), ('\u{3280}', '\u{3289}'), ('\u{32b1}',
+ '\u{32bf}'), ('\u{a620}', '\u{a629}'), ('\u{a6e6}', '\u{a6ef}'), ('\u{a830}', '\u{a835}'),
+ ('\u{a8d0}', '\u{a8d9}'), ('\u{a900}', '\u{a909}'), ('\u{a9d0}', '\u{a9d9}'), ('\u{a9f0}',
+ '\u{a9f9}'), ('\u{aa50}', '\u{aa59}'), ('\u{abf0}', '\u{abf9}'), ('\u{ff10}', '\u{ff19}'),
+ ('\u{10107}', '\u{10133}'), ('\u{10140}', '\u{10178}'), ('\u{1018a}', '\u{1018b}'),
+ ('\u{102e1}', '\u{102fb}'), ('\u{10320}', '\u{10323}'), ('\u{10341}', '\u{10341}'),
+ ('\u{1034a}', '\u{1034a}'), ('\u{103d1}', '\u{103d5}'), ('\u{104a0}', '\u{104a9}'),
+ ('\u{10858}', '\u{1085f}'), ('\u{10879}', '\u{1087f}'), ('\u{108a7}', '\u{108af}'),
+ ('\u{108fb}', '\u{108ff}'), ('\u{10916}', '\u{1091b}'), ('\u{109bc}', '\u{109bd}'),
+ ('\u{109c0}', '\u{109cf}'), ('\u{109d2}', '\u{109ff}'), ('\u{10a40}', '\u{10a48}'),
+ ('\u{10a7d}', '\u{10a7e}'), ('\u{10a9d}', '\u{10a9f}'), ('\u{10aeb}', '\u{10aef}'),
+ ('\u{10b58}', '\u{10b5f}'), ('\u{10b78}', '\u{10b7f}'), ('\u{10ba9}', '\u{10baf}'),
+ ('\u{10cfa}', '\u{10cff}'), ('\u{10d30}', '\u{10d39}'), ('\u{10e60}', '\u{10e7e}'),
+ ('\u{10f1d}', '\u{10f26}'), ('\u{10f51}', '\u{10f54}'), ('\u{11052}', '\u{1106f}'),
+ ('\u{110f0}', '\u{110f9}'), ('\u{11136}', '\u{1113f}'), ('\u{111d0}', '\u{111d9}'),
+ ('\u{111e1}', '\u{111f4}'), ('\u{112f0}', '\u{112f9}'), ('\u{11450}', '\u{11459}'),
+ ('\u{114d0}', '\u{114d9}'), ('\u{11650}', '\u{11659}'), ('\u{116c0}', '\u{116c9}'),
+ ('\u{11730}', '\u{1173b}'), ('\u{118e0}', '\u{118f2}'), ('\u{11c50}', '\u{11c6c}'),
+ ('\u{11d50}', '\u{11d59}'), ('\u{11da0}', '\u{11da9}'), ('\u{11fc0}', '\u{11fd4}'),
+ ('\u{12400}', '\u{1246e}'), ('\u{16a60}', '\u{16a69}'), ('\u{16b50}', '\u{16b59}'),
+ ('\u{16b5b}', '\u{16b61}'), ('\u{16e80}', '\u{16e96}'), ('\u{1d2e0}', '\u{1d2f3}'),
+ ('\u{1d360}', '\u{1d378}'), ('\u{1d7ce}', '\u{1d7ff}'), ('\u{1e140}', '\u{1e149}'),
+ ('\u{1e2f0}', '\u{1e2f9}'), ('\u{1e8c7}', '\u{1e8cf}'), ('\u{1e950}', '\u{1e959}'),
+ ('\u{1ec71}', '\u{1ecab}'), ('\u{1ecad}', '\u{1ecaf}'), ('\u{1ecb1}', '\u{1ecb4}'),
+ ('\u{1ed01}', '\u{1ed2d}'), ('\u{1ed2f}', '\u{1ed3d}'), ('\u{1f100}', '\u{1f10c}')
+ ];
+
+ #[inline]
+ pub fn N(c: char) -> bool {
+ super::util::bsearch_range_table(c, N_table)
+ }
+
+}
+
+mod derived_property {
+ const Alphabetic_table: &'static [(char, char)] = &[
+ ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'),
+ ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'),
+ ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}',
+ '\u{2ee}'), ('\u{345}', '\u{345}'), ('\u{370}', '\u{374}'), ('\u{376}', '\u{377}'),
+ ('\u{37a}', '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}',
+ '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'),
+ ('\u{3f7}', '\u{481}'), ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{559}',
+ '\u{559}'), ('\u{560}', '\u{588}'), ('\u{5b0}', '\u{5bd}'), ('\u{5bf}', '\u{5bf}'),
+ ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), ('\u{5d0}',
+ '\u{5ea}'), ('\u{5ef}', '\u{5f2}'), ('\u{610}', '\u{61a}'), ('\u{620}', '\u{657}'),
+ ('\u{659}', '\u{65f}'), ('\u{66e}', '\u{6d3}'), ('\u{6d5}', '\u{6dc}'), ('\u{6e1}',
+ '\u{6e8}'), ('\u{6ed}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'),
+ ('\u{710}', '\u{73f}'), ('\u{74d}', '\u{7b1}'), ('\u{7ca}', '\u{7ea}'), ('\u{7f4}',
+ '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), ('\u{800}', '\u{817}'), ('\u{81a}', '\u{82c}'),
+ ('\u{840}', '\u{858}'), ('\u{860}', '\u{86a}'), ('\u{8a0}', '\u{8b4}'), ('\u{8b6}',
+ '\u{8bd}'), ('\u{8d4}', '\u{8df}'), ('\u{8e3}', '\u{8e9}'), ('\u{8f0}', '\u{93b}'),
+ ('\u{93d}', '\u{94c}'), ('\u{94e}', '\u{950}'), ('\u{955}', '\u{963}'), ('\u{971}',
+ '\u{983}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', '\u{9a8}'),
+ ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), ('\u{9bd}',
+ '\u{9c4}'), ('\u{9c7}', '\u{9c8}'), ('\u{9cb}', '\u{9cc}'), ('\u{9ce}', '\u{9ce}'),
+ ('\u{9d7}', '\u{9d7}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e3}'), ('\u{9f0}',
+ '\u{9f1}'), ('\u{9fc}', '\u{9fc}'), ('\u{a01}', '\u{a03}'), ('\u{a05}', '\u{a0a}'),
+ ('\u{a0f}', '\u{a10}'), ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}',
+ '\u{a33}'), ('\u{a35}', '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a3e}', '\u{a42}'),
+ ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4c}'), ('\u{a51}', '\u{a51}'), ('\u{a59}',
+ '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a70}', '\u{a75}'), ('\u{a81}', '\u{a83}'),
+ ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), ('\u{aaa}',
+ '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abd}', '\u{ac5}'),
+ ('\u{ac7}', '\u{ac9}'), ('\u{acb}', '\u{acc}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}',
+ '\u{ae3}'), ('\u{af9}', '\u{afc}'), ('\u{b01}', '\u{b03}'), ('\u{b05}', '\u{b0c}'),
+ ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), ('\u{b32}',
+ '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3d}', '\u{b44}'), ('\u{b47}', '\u{b48}'),
+ ('\u{b4b}', '\u{b4c}'), ('\u{b56}', '\u{b57}'), ('\u{b5c}', '\u{b5d}'), ('\u{b5f}',
+ '\u{b63}'), ('\u{b71}', '\u{b71}'), ('\u{b82}', '\u{b83}'), ('\u{b85}', '\u{b8a}'),
+ ('\u{b8e}', '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', '\u{b9a}'), ('\u{b9c}',
+ '\u{b9c}'), ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), ('\u{ba8}', '\u{baa}'),
+ ('\u{bae}', '\u{bb9}'), ('\u{bbe}', '\u{bc2}'), ('\u{bc6}', '\u{bc8}'), ('\u{bca}',
+ '\u{bcc}'), ('\u{bd0}', '\u{bd0}'), ('\u{bd7}', '\u{bd7}'), ('\u{c00}', '\u{c03}'),
+ ('\u{c05}', '\u{c0c}'), ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}',
+ '\u{c39}'), ('\u{c3d}', '\u{c44}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4c}'),
+ ('\u{c55}', '\u{c56}'), ('\u{c58}', '\u{c5a}'), ('\u{c60}', '\u{c63}'), ('\u{c80}',
+ '\u{c83}'), ('\u{c85}', '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'),
+ ('\u{caa}', '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), ('\u{cbd}', '\u{cc4}'), ('\u{cc6}',
+ '\u{cc8}'), ('\u{cca}', '\u{ccc}'), ('\u{cd5}', '\u{cd6}'), ('\u{cde}', '\u{cde}'),
+ ('\u{ce0}', '\u{ce3}'), ('\u{cf1}', '\u{cf2}'), ('\u{d00}', '\u{d03}'), ('\u{d05}',
+ '\u{d0c}'), ('\u{d0e}', '\u{d10}'), ('\u{d12}', '\u{d3a}'), ('\u{d3d}', '\u{d44}'),
+ ('\u{d46}', '\u{d48}'), ('\u{d4a}', '\u{d4c}'), ('\u{d4e}', '\u{d4e}'), ('\u{d54}',
+ '\u{d57}'), ('\u{d5f}', '\u{d63}'), ('\u{d7a}', '\u{d7f}'), ('\u{d82}', '\u{d83}'),
+ ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', '\u{dbb}'), ('\u{dbd}',
+ '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'),
+ ('\u{dd8}', '\u{ddf}'), ('\u{df2}', '\u{df3}'), ('\u{e01}', '\u{e3a}'), ('\u{e40}',
+ '\u{e46}'), ('\u{e4d}', '\u{e4d}'), ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'),
+ ('\u{e86}', '\u{e8a}'), ('\u{e8c}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}',
+ '\u{eb9}'), ('\u{ebb}', '\u{ebd}'), ('\u{ec0}', '\u{ec4}'), ('\u{ec6}', '\u{ec6}'),
+ ('\u{ecd}', '\u{ecd}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', '\u{f00}'), ('\u{f40}',
+ '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f71}', '\u{f81}'), ('\u{f88}', '\u{f97}'),
+ ('\u{f99}', '\u{fbc}'), ('\u{1000}', '\u{1036}'), ('\u{1038}', '\u{1038}'), ('\u{103b}',
+ '\u{103f}'), ('\u{1050}', '\u{108f}'), ('\u{109a}', '\u{109d}'), ('\u{10a0}', '\u{10c5}'),
+ ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{10d0}', '\u{10fa}'), ('\u{10fc}',
+ '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', '\u{1256}'), ('\u{1258}', '\u{1258}'),
+ ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), ('\u{128a}', '\u{128d}'), ('\u{1290}',
+ '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', '\u{12be}'), ('\u{12c0}', '\u{12c0}'),
+ ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), ('\u{12d8}', '\u{1310}'), ('\u{1312}',
+ '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', '\u{13f5}'),
+ ('\u{13f8}', '\u{13fd}'), ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}',
+ '\u{169a}'), ('\u{16a0}', '\u{16ea}'), ('\u{16ee}', '\u{16f8}'), ('\u{1700}', '\u{170c}'),
+ ('\u{170e}', '\u{1713}'), ('\u{1720}', '\u{1733}'), ('\u{1740}', '\u{1753}'), ('\u{1760}',
+ '\u{176c}'), ('\u{176e}', '\u{1770}'), ('\u{1772}', '\u{1773}'), ('\u{1780}', '\u{17b3}'),
+ ('\u{17b6}', '\u{17c8}'), ('\u{17d7}', '\u{17d7}'), ('\u{17dc}', '\u{17dc}'), ('\u{1820}',
+ '\u{1878}'), ('\u{1880}', '\u{18aa}'), ('\u{18b0}', '\u{18f5}'), ('\u{1900}', '\u{191e}'),
+ ('\u{1920}', '\u{192b}'), ('\u{1930}', '\u{1938}'), ('\u{1950}', '\u{196d}'), ('\u{1970}',
+ '\u{1974}'), ('\u{1980}', '\u{19ab}'), ('\u{19b0}', '\u{19c9}'), ('\u{1a00}', '\u{1a1b}'),
+ ('\u{1a20}', '\u{1a5e}'), ('\u{1a61}', '\u{1a74}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1b00}',
+ '\u{1b33}'), ('\u{1b35}', '\u{1b43}'), ('\u{1b45}', '\u{1b4b}'), ('\u{1b80}', '\u{1ba9}'),
+ ('\u{1bac}', '\u{1baf}'), ('\u{1bba}', '\u{1be5}'), ('\u{1be7}', '\u{1bf1}'), ('\u{1c00}',
+ '\u{1c36}'), ('\u{1c4d}', '\u{1c4f}'), ('\u{1c5a}', '\u{1c7d}'), ('\u{1c80}', '\u{1c88}'),
+ ('\u{1c90}', '\u{1cba}'), ('\u{1cbd}', '\u{1cbf}'), ('\u{1ce9}', '\u{1cec}'), ('\u{1cee}',
+ '\u{1cf3}'), ('\u{1cf5}', '\u{1cf6}'), ('\u{1cfa}', '\u{1cfa}'), ('\u{1d00}', '\u{1dbf}'),
+ ('\u{1de7}', '\u{1df4}'), ('\u{1e00}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}',
+ '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'),
+ ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}',
+ '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'),
+ ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}',
+ '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), ('\u{2071}', '\u{2071}'),
+ ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{2102}', '\u{2102}'), ('\u{2107}',
+ '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}', '\u{2115}'), ('\u{2119}', '\u{211d}'),
+ ('\u{2124}', '\u{2124}'), ('\u{2126}', '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}',
+ '\u{212d}'), ('\u{212f}', '\u{2139}'), ('\u{213c}', '\u{213f}'), ('\u{2145}', '\u{2149}'),
+ ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2188}'), ('\u{24b6}', '\u{24e9}'), ('\u{2c00}',
+ '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cee}'),
+ ('\u{2cf2}', '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}',
+ '\u{2d2d}'), ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2d80}', '\u{2d96}'),
+ ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), ('\u{2db8}',
+ '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'),
+ ('\u{2dd8}', '\u{2dde}'), ('\u{2de0}', '\u{2dff}'), ('\u{2e2f}', '\u{2e2f}'), ('\u{3005}',
+ '\u{3007}'), ('\u{3021}', '\u{3029}'), ('\u{3031}', '\u{3035}'), ('\u{3038}', '\u{303c}'),
+ ('\u{3041}', '\u{3096}'), ('\u{309d}', '\u{309f}'), ('\u{30a1}', '\u{30fa}'), ('\u{30fc}',
+ '\u{30ff}'), ('\u{3105}', '\u{312f}'), ('\u{3131}', '\u{318e}'), ('\u{31a0}', '\u{31ba}'),
+ ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'), ('\u{4e00}', '\u{9fef}'), ('\u{a000}',
+ '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), ('\u{a500}', '\u{a60c}'), ('\u{a610}', '\u{a61f}'),
+ ('\u{a62a}', '\u{a62b}'), ('\u{a640}', '\u{a66e}'), ('\u{a674}', '\u{a67b}'), ('\u{a67f}',
+ '\u{a6ef}'), ('\u{a717}', '\u{a71f}'), ('\u{a722}', '\u{a788}'), ('\u{a78b}', '\u{a7bf}'),
+ ('\u{a7c2}', '\u{a7c6}'), ('\u{a7f7}', '\u{a805}'), ('\u{a807}', '\u{a827}'), ('\u{a840}',
+ '\u{a873}'), ('\u{a880}', '\u{a8c3}'), ('\u{a8c5}', '\u{a8c5}'), ('\u{a8f2}', '\u{a8f7}'),
+ ('\u{a8fb}', '\u{a8fb}'), ('\u{a8fd}', '\u{a8ff}'), ('\u{a90a}', '\u{a92a}'), ('\u{a930}',
+ '\u{a952}'), ('\u{a960}', '\u{a97c}'), ('\u{a980}', '\u{a9b2}'), ('\u{a9b4}', '\u{a9bf}'),
+ ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e0}', '\u{a9ef}'), ('\u{a9fa}', '\u{a9fe}'), ('\u{aa00}',
+ '\u{aa36}'), ('\u{aa40}', '\u{aa4d}'), ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', '\u{aabe}'),
+ ('\u{aac0}', '\u{aac0}'), ('\u{aac2}', '\u{aac2}'), ('\u{aadb}', '\u{aadd}'), ('\u{aae0}',
+ '\u{aaef}'), ('\u{aaf2}', '\u{aaf5}'), ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'),
+ ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), ('\u{ab30}',
+ '\u{ab5a}'), ('\u{ab5c}', '\u{ab67}'), ('\u{ab70}', '\u{abea}'), ('\u{ac00}', '\u{d7a3}'),
+ ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), ('\u{fa70}',
+ '\u{fad9}'), ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', '\u{fb28}'),
+ ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}',
+ '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'), ('\u{fbd3}', '\u{fd3d}'),
+ ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), ('\u{fdf0}', '\u{fdfb}'), ('\u{fe70}',
+ '\u{fe74}'), ('\u{fe76}', '\u{fefc}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'),
+ ('\u{ff66}', '\u{ffbe}'), ('\u{ffc2}', '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}',
+ '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), ('\u{10000}', '\u{1000b}'), ('\u{1000d}',
+ '\u{10026}'), ('\u{10028}', '\u{1003a}'), ('\u{1003c}', '\u{1003d}'), ('\u{1003f}',
+ '\u{1004d}'), ('\u{10050}', '\u{1005d}'), ('\u{10080}', '\u{100fa}'), ('\u{10140}',
+ '\u{10174}'), ('\u{10280}', '\u{1029c}'), ('\u{102a0}', '\u{102d0}'), ('\u{10300}',
+ '\u{1031f}'), ('\u{1032d}', '\u{1034a}'), ('\u{10350}', '\u{1037a}'), ('\u{10380}',
+ '\u{1039d}'), ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', '\u{103cf}'), ('\u{103d1}',
+ '\u{103d5}'), ('\u{10400}', '\u{1049d}'), ('\u{104b0}', '\u{104d3}'), ('\u{104d8}',
+ '\u{104fb}'), ('\u{10500}', '\u{10527}'), ('\u{10530}', '\u{10563}'), ('\u{10600}',
+ '\u{10736}'), ('\u{10740}', '\u{10755}'), ('\u{10760}', '\u{10767}'), ('\u{10800}',
+ '\u{10805}'), ('\u{10808}', '\u{10808}'), ('\u{1080a}', '\u{10835}'), ('\u{10837}',
+ '\u{10838}'), ('\u{1083c}', '\u{1083c}'), ('\u{1083f}', '\u{10855}'), ('\u{10860}',
+ '\u{10876}'), ('\u{10880}', '\u{1089e}'), ('\u{108e0}', '\u{108f2}'), ('\u{108f4}',
+ '\u{108f5}'), ('\u{10900}', '\u{10915}'), ('\u{10920}', '\u{10939}'), ('\u{10980}',
+ '\u{109b7}'), ('\u{109be}', '\u{109bf}'), ('\u{10a00}', '\u{10a03}'), ('\u{10a05}',
+ '\u{10a06}'), ('\u{10a0c}', '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), ('\u{10a19}',
+ '\u{10a35}'), ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', '\u{10a9c}'), ('\u{10ac0}',
+ '\u{10ac7}'), ('\u{10ac9}', '\u{10ae4}'), ('\u{10b00}', '\u{10b35}'), ('\u{10b40}',
+ '\u{10b55}'), ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', '\u{10b91}'), ('\u{10c00}',
+ '\u{10c48}'), ('\u{10c80}', '\u{10cb2}'), ('\u{10cc0}', '\u{10cf2}'), ('\u{10d00}',
+ '\u{10d27}'), ('\u{10f00}', '\u{10f1c}'), ('\u{10f27}', '\u{10f27}'), ('\u{10f30}',
+ '\u{10f45}'), ('\u{10fe0}', '\u{10ff6}'), ('\u{11000}', '\u{11045}'), ('\u{11082}',
+ '\u{110b8}'), ('\u{110d0}', '\u{110e8}'), ('\u{11100}', '\u{11132}'), ('\u{11144}',
+ '\u{11146}'), ('\u{11150}', '\u{11172}'), ('\u{11176}', '\u{11176}'), ('\u{11180}',
+ '\u{111bf}'), ('\u{111c1}', '\u{111c4}'), ('\u{111da}', '\u{111da}'), ('\u{111dc}',
+ '\u{111dc}'), ('\u{11200}', '\u{11211}'), ('\u{11213}', '\u{11234}'), ('\u{11237}',
+ '\u{11237}'), ('\u{1123e}', '\u{1123e}'), ('\u{11280}', '\u{11286}'), ('\u{11288}',
+ '\u{11288}'), ('\u{1128a}', '\u{1128d}'), ('\u{1128f}', '\u{1129d}'), ('\u{1129f}',
+ '\u{112a8}'), ('\u{112b0}', '\u{112e8}'), ('\u{11300}', '\u{11303}'), ('\u{11305}',
+ '\u{1130c}'), ('\u{1130f}', '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}',
+ '\u{11330}'), ('\u{11332}', '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133d}',
+ '\u{11344}'), ('\u{11347}', '\u{11348}'), ('\u{1134b}', '\u{1134c}'), ('\u{11350}',
+ '\u{11350}'), ('\u{11357}', '\u{11357}'), ('\u{1135d}', '\u{11363}'), ('\u{11400}',
+ '\u{11441}'), ('\u{11443}', '\u{11445}'), ('\u{11447}', '\u{1144a}'), ('\u{1145f}',
+ '\u{1145f}'), ('\u{11480}', '\u{114c1}'), ('\u{114c4}', '\u{114c5}'), ('\u{114c7}',
+ '\u{114c7}'), ('\u{11580}', '\u{115b5}'), ('\u{115b8}', '\u{115be}'), ('\u{115d8}',
+ '\u{115dd}'), ('\u{11600}', '\u{1163e}'), ('\u{11640}', '\u{11640}'), ('\u{11644}',
+ '\u{11644}'), ('\u{11680}', '\u{116b5}'), ('\u{116b8}', '\u{116b8}'), ('\u{11700}',
+ '\u{1171a}'), ('\u{1171d}', '\u{1172a}'), ('\u{11800}', '\u{11838}'), ('\u{118a0}',
+ '\u{118df}'), ('\u{118ff}', '\u{118ff}'), ('\u{119a0}', '\u{119a7}'), ('\u{119aa}',
+ '\u{119d7}'), ('\u{119da}', '\u{119df}'), ('\u{119e1}', '\u{119e1}'), ('\u{119e3}',
+ '\u{119e4}'), ('\u{11a00}', '\u{11a32}'), ('\u{11a35}', '\u{11a3e}'), ('\u{11a50}',
+ '\u{11a97}'), ('\u{11a9d}', '\u{11a9d}'), ('\u{11ac0}', '\u{11af8}'), ('\u{11c00}',
+ '\u{11c08}'), ('\u{11c0a}', '\u{11c36}'), ('\u{11c38}', '\u{11c3e}'), ('\u{11c40}',
+ '\u{11c40}'), ('\u{11c72}', '\u{11c8f}'), ('\u{11c92}', '\u{11ca7}'), ('\u{11ca9}',
+ '\u{11cb6}'), ('\u{11d00}', '\u{11d06}'), ('\u{11d08}', '\u{11d09}'), ('\u{11d0b}',
+ '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}',
+ '\u{11d41}'), ('\u{11d43}', '\u{11d43}'), ('\u{11d46}', '\u{11d47}'), ('\u{11d60}',
+ '\u{11d65}'), ('\u{11d67}', '\u{11d68}'), ('\u{11d6a}', '\u{11d8e}'), ('\u{11d90}',
+ '\u{11d91}'), ('\u{11d93}', '\u{11d96}'), ('\u{11d98}', '\u{11d98}'), ('\u{11ee0}',
+ '\u{11ef6}'), ('\u{12000}', '\u{12399}'), ('\u{12400}', '\u{1246e}'), ('\u{12480}',
+ '\u{12543}'), ('\u{13000}', '\u{1342e}'), ('\u{14400}', '\u{14646}'), ('\u{16800}',
+ '\u{16a38}'), ('\u{16a40}', '\u{16a5e}'), ('\u{16ad0}', '\u{16aed}'), ('\u{16b00}',
+ '\u{16b2f}'), ('\u{16b40}', '\u{16b43}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}',
+ '\u{16b8f}'), ('\u{16e40}', '\u{16e7f}'), ('\u{16f00}', '\u{16f4a}'), ('\u{16f4f}',
+ '\u{16f87}'), ('\u{16f8f}', '\u{16f9f}'), ('\u{16fe0}', '\u{16fe1}'), ('\u{16fe3}',
+ '\u{16fe3}'), ('\u{17000}', '\u{187f7}'), ('\u{18800}', '\u{18af2}'), ('\u{1b000}',
+ '\u{1b11e}'), ('\u{1b150}', '\u{1b152}'), ('\u{1b164}', '\u{1b167}'), ('\u{1b170}',
+ '\u{1b2fb}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}',
+ '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1bc9e}', '\u{1bc9e}'), ('\u{1d400}',
+ '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}',
+ '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}',
+ '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}',
+ '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}',
+ '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}',
+ '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}',
+ '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}',
+ '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}',
+ '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}',
+ '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1e000}',
+ '\u{1e006}'), ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), ('\u{1e023}',
+ '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), ('\u{1e100}', '\u{1e12c}'), ('\u{1e137}',
+ '\u{1e13d}'), ('\u{1e14e}', '\u{1e14e}'), ('\u{1e2c0}', '\u{1e2eb}'), ('\u{1e800}',
+ '\u{1e8c4}'), ('\u{1e900}', '\u{1e943}'), ('\u{1e947}', '\u{1e947}'), ('\u{1e94b}',
+ '\u{1e94b}'), ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}',
+ '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}',
+ '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}',
+ '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}',
+ '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}',
+ '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}',
+ '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}',
+ '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}',
+ '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}',
+ '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}',
+ '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}',
+ '\u{1eebb}'), ('\u{1f130}', '\u{1f149}'), ('\u{1f150}', '\u{1f169}'), ('\u{1f170}',
+ '\u{1f189}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), ('\u{2b740}',
+ '\u{2b81d}'), ('\u{2b820}', '\u{2cea1}'), ('\u{2ceb0}', '\u{2ebe0}'), ('\u{2f800}',
+ '\u{2fa1d}')
+ ];
+
+ #[inline]
+ pub fn Alphabetic(c: char) -> bool {
+ super::util::bsearch_range_table(c, Alphabetic_table)
+ }
+
+}
+
+pub mod grapheme {
+ use core::result::Result::{Ok, Err};
+
+ pub use self::GraphemeCat::*;
+
+ #[allow(non_camel_case_types)]
+ #[derive(Clone, Copy, PartialEq, Eq, Debug)]
+ pub enum GraphemeCat {
+ GC_Any,
+ GC_CR,
+ GC_Control,
+ GC_Extend,
+ GC_Extended_Pictographic,
+ GC_L,
+ GC_LF,
+ GC_LV,
+ GC_LVT,
+ GC_Prepend,
+ GC_Regional_Indicator,
+ GC_SpacingMark,
+ GC_T,
+ GC_V,
+ GC_ZWJ,
+ }
+
+ fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ match r.binary_search_by(|&(lo, hi, _)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }) {
+ Ok(idx) => {
+ let (_, _, cat) = r[idx];
+ cat
+ }
+ Err(_) => GC_Any
+ }
+ }
+
+ pub fn grapheme_category(c: char) -> GraphemeCat {
+ bsearch_range_value_table(c, grapheme_cat_table)
+ }
+
+ const grapheme_cat_table: &'static [(char, char, GraphemeCat)] = &[
+ ('\u{0}', '\u{9}', GC_Control), ('\u{a}', '\u{a}', GC_LF), ('\u{b}', '\u{c}', GC_Control),
+ ('\u{d}', '\u{d}', GC_CR), ('\u{e}', '\u{1f}', GC_Control), ('\u{7f}', '\u{9f}',
+ GC_Control), ('\u{a9}', '\u{a9}', GC_Extended_Pictographic), ('\u{ad}', '\u{ad}',
+ GC_Control), ('\u{ae}', '\u{ae}', GC_Extended_Pictographic), ('\u{300}', '\u{36f}',
+ GC_Extend), ('\u{483}', '\u{489}', GC_Extend), ('\u{591}', '\u{5bd}', GC_Extend),
+ ('\u{5bf}', '\u{5bf}', GC_Extend), ('\u{5c1}', '\u{5c2}', GC_Extend), ('\u{5c4}', '\u{5c5}',
+ GC_Extend), ('\u{5c7}', '\u{5c7}', GC_Extend), ('\u{600}', '\u{605}', GC_Prepend),
+ ('\u{610}', '\u{61a}', GC_Extend), ('\u{61c}', '\u{61c}', GC_Control), ('\u{64b}',
+ '\u{65f}', GC_Extend), ('\u{670}', '\u{670}', GC_Extend), ('\u{6d6}', '\u{6dc}', GC_Extend),
+ ('\u{6dd}', '\u{6dd}', GC_Prepend), ('\u{6df}', '\u{6e4}', GC_Extend), ('\u{6e7}',
+ '\u{6e8}', GC_Extend), ('\u{6ea}', '\u{6ed}', GC_Extend), ('\u{70f}', '\u{70f}',
+ GC_Prepend), ('\u{711}', '\u{711}', GC_Extend), ('\u{730}', '\u{74a}', GC_Extend),
+ ('\u{7a6}', '\u{7b0}', GC_Extend), ('\u{7eb}', '\u{7f3}', GC_Extend), ('\u{7fd}', '\u{7fd}',
+ GC_Extend), ('\u{816}', '\u{819}', GC_Extend), ('\u{81b}', '\u{823}', GC_Extend),
+ ('\u{825}', '\u{827}', GC_Extend), ('\u{829}', '\u{82d}', GC_Extend), ('\u{859}', '\u{85b}',
+ GC_Extend), ('\u{8d3}', '\u{8e1}', GC_Extend), ('\u{8e2}', '\u{8e2}', GC_Prepend),
+ ('\u{8e3}', '\u{902}', GC_Extend), ('\u{903}', '\u{903}', GC_SpacingMark), ('\u{93a}',
+ '\u{93a}', GC_Extend), ('\u{93b}', '\u{93b}', GC_SpacingMark), ('\u{93c}', '\u{93c}',
+ GC_Extend), ('\u{93e}', '\u{940}', GC_SpacingMark), ('\u{941}', '\u{948}', GC_Extend),
+ ('\u{949}', '\u{94c}', GC_SpacingMark), ('\u{94d}', '\u{94d}', GC_Extend), ('\u{94e}',
+ '\u{94f}', GC_SpacingMark), ('\u{951}', '\u{957}', GC_Extend), ('\u{962}', '\u{963}',
+ GC_Extend), ('\u{981}', '\u{981}', GC_Extend), ('\u{982}', '\u{983}', GC_SpacingMark),
+ ('\u{9bc}', '\u{9bc}', GC_Extend), ('\u{9be}', '\u{9be}', GC_Extend), ('\u{9bf}', '\u{9c0}',
+ GC_SpacingMark), ('\u{9c1}', '\u{9c4}', GC_Extend), ('\u{9c7}', '\u{9c8}', GC_SpacingMark),
+ ('\u{9cb}', '\u{9cc}', GC_SpacingMark), ('\u{9cd}', '\u{9cd}', GC_Extend), ('\u{9d7}',
+ '\u{9d7}', GC_Extend), ('\u{9e2}', '\u{9e3}', GC_Extend), ('\u{9fe}', '\u{9fe}', GC_Extend),
+ ('\u{a01}', '\u{a02}', GC_Extend), ('\u{a03}', '\u{a03}', GC_SpacingMark), ('\u{a3c}',
+ '\u{a3c}', GC_Extend), ('\u{a3e}', '\u{a40}', GC_SpacingMark), ('\u{a41}', '\u{a42}',
+ GC_Extend), ('\u{a47}', '\u{a48}', GC_Extend), ('\u{a4b}', '\u{a4d}', GC_Extend),
+ ('\u{a51}', '\u{a51}', GC_Extend), ('\u{a70}', '\u{a71}', GC_Extend), ('\u{a75}', '\u{a75}',
+ GC_Extend), ('\u{a81}', '\u{a82}', GC_Extend), ('\u{a83}', '\u{a83}', GC_SpacingMark),
+ ('\u{abc}', '\u{abc}', GC_Extend), ('\u{abe}', '\u{ac0}', GC_SpacingMark), ('\u{ac1}',
+ '\u{ac5}', GC_Extend), ('\u{ac7}', '\u{ac8}', GC_Extend), ('\u{ac9}', '\u{ac9}',
+ GC_SpacingMark), ('\u{acb}', '\u{acc}', GC_SpacingMark), ('\u{acd}', '\u{acd}', GC_Extend),
+ ('\u{ae2}', '\u{ae3}', GC_Extend), ('\u{afa}', '\u{aff}', GC_Extend), ('\u{b01}', '\u{b01}',
+ GC_Extend), ('\u{b02}', '\u{b03}', GC_SpacingMark), ('\u{b3c}', '\u{b3c}', GC_Extend),
+ ('\u{b3e}', '\u{b3f}', GC_Extend), ('\u{b40}', '\u{b40}', GC_SpacingMark), ('\u{b41}',
+ '\u{b44}', GC_Extend), ('\u{b47}', '\u{b48}', GC_SpacingMark), ('\u{b4b}', '\u{b4c}',
+ GC_SpacingMark), ('\u{b4d}', '\u{b4d}', GC_Extend), ('\u{b56}', '\u{b57}', GC_Extend),
+ ('\u{b62}', '\u{b63}', GC_Extend), ('\u{b82}', '\u{b82}', GC_Extend), ('\u{bbe}', '\u{bbe}',
+ GC_Extend), ('\u{bbf}', '\u{bbf}', GC_SpacingMark), ('\u{bc0}', '\u{bc0}', GC_Extend),
+ ('\u{bc1}', '\u{bc2}', GC_SpacingMark), ('\u{bc6}', '\u{bc8}', GC_SpacingMark), ('\u{bca}',
+ '\u{bcc}', GC_SpacingMark), ('\u{bcd}', '\u{bcd}', GC_Extend), ('\u{bd7}', '\u{bd7}',
+ GC_Extend), ('\u{c00}', '\u{c00}', GC_Extend), ('\u{c01}', '\u{c03}', GC_SpacingMark),
+ ('\u{c04}', '\u{c04}', GC_Extend), ('\u{c3e}', '\u{c40}', GC_Extend), ('\u{c41}', '\u{c44}',
+ GC_SpacingMark), ('\u{c46}', '\u{c48}', GC_Extend), ('\u{c4a}', '\u{c4d}', GC_Extend),
+ ('\u{c55}', '\u{c56}', GC_Extend), ('\u{c62}', '\u{c63}', GC_Extend), ('\u{c81}', '\u{c81}',
+ GC_Extend), ('\u{c82}', '\u{c83}', GC_SpacingMark), ('\u{cbc}', '\u{cbc}', GC_Extend),
+ ('\u{cbe}', '\u{cbe}', GC_SpacingMark), ('\u{cbf}', '\u{cbf}', GC_Extend), ('\u{cc0}',
+ '\u{cc1}', GC_SpacingMark), ('\u{cc2}', '\u{cc2}', GC_Extend), ('\u{cc3}', '\u{cc4}',
+ GC_SpacingMark), ('\u{cc6}', '\u{cc6}', GC_Extend), ('\u{cc7}', '\u{cc8}', GC_SpacingMark),
+ ('\u{cca}', '\u{ccb}', GC_SpacingMark), ('\u{ccc}', '\u{ccd}', GC_Extend), ('\u{cd5}',
+ '\u{cd6}', GC_Extend), ('\u{ce2}', '\u{ce3}', GC_Extend), ('\u{d00}', '\u{d01}', GC_Extend),
+ ('\u{d02}', '\u{d03}', GC_SpacingMark), ('\u{d3b}', '\u{d3c}', GC_Extend), ('\u{d3e}',
+ '\u{d3e}', GC_Extend), ('\u{d3f}', '\u{d40}', GC_SpacingMark), ('\u{d41}', '\u{d44}',
+ GC_Extend), ('\u{d46}', '\u{d48}', GC_SpacingMark), ('\u{d4a}', '\u{d4c}', GC_SpacingMark),
+ ('\u{d4d}', '\u{d4d}', GC_Extend), ('\u{d4e}', '\u{d4e}', GC_Prepend), ('\u{d57}',
+ '\u{d57}', GC_Extend), ('\u{d62}', '\u{d63}', GC_Extend), ('\u{d82}', '\u{d83}',
+ GC_SpacingMark), ('\u{dca}', '\u{dca}', GC_Extend), ('\u{dcf}', '\u{dcf}', GC_Extend),
+ ('\u{dd0}', '\u{dd1}', GC_SpacingMark), ('\u{dd2}', '\u{dd4}', GC_Extend), ('\u{dd6}',
+ '\u{dd6}', GC_Extend), ('\u{dd8}', '\u{dde}', GC_SpacingMark), ('\u{ddf}', '\u{ddf}',
+ GC_Extend), ('\u{df2}', '\u{df3}', GC_SpacingMark), ('\u{e31}', '\u{e31}', GC_Extend),
+ ('\u{e33}', '\u{e33}', GC_SpacingMark), ('\u{e34}', '\u{e3a}', GC_Extend), ('\u{e47}',
+ '\u{e4e}', GC_Extend), ('\u{eb1}', '\u{eb1}', GC_Extend), ('\u{eb3}', '\u{eb3}',
+ GC_SpacingMark), ('\u{eb4}', '\u{ebc}', GC_Extend), ('\u{ec8}', '\u{ecd}', GC_Extend),
+ ('\u{f18}', '\u{f19}', GC_Extend), ('\u{f35}', '\u{f35}', GC_Extend), ('\u{f37}', '\u{f37}',
+ GC_Extend), ('\u{f39}', '\u{f39}', GC_Extend), ('\u{f3e}', '\u{f3f}', GC_SpacingMark),
+ ('\u{f71}', '\u{f7e}', GC_Extend), ('\u{f7f}', '\u{f7f}', GC_SpacingMark), ('\u{f80}',
+ '\u{f84}', GC_Extend), ('\u{f86}', '\u{f87}', GC_Extend), ('\u{f8d}', '\u{f97}', GC_Extend),
+ ('\u{f99}', '\u{fbc}', GC_Extend), ('\u{fc6}', '\u{fc6}', GC_Extend), ('\u{102d}',
+ '\u{1030}', GC_Extend), ('\u{1031}', '\u{1031}', GC_SpacingMark), ('\u{1032}', '\u{1037}',
+ GC_Extend), ('\u{1039}', '\u{103a}', GC_Extend), ('\u{103b}', '\u{103c}', GC_SpacingMark),
+ ('\u{103d}', '\u{103e}', GC_Extend), ('\u{1056}', '\u{1057}', GC_SpacingMark), ('\u{1058}',
+ '\u{1059}', GC_Extend), ('\u{105e}', '\u{1060}', GC_Extend), ('\u{1071}', '\u{1074}',
+ GC_Extend), ('\u{1082}', '\u{1082}', GC_Extend), ('\u{1084}', '\u{1084}', GC_SpacingMark),
+ ('\u{1085}', '\u{1086}', GC_Extend), ('\u{108d}', '\u{108d}', GC_Extend), ('\u{109d}',
+ '\u{109d}', GC_Extend), ('\u{1100}', '\u{115f}', GC_L), ('\u{1160}', '\u{11a7}', GC_V),
+ ('\u{11a8}', '\u{11ff}', GC_T), ('\u{135d}', '\u{135f}', GC_Extend), ('\u{1712}',
+ '\u{1714}', GC_Extend), ('\u{1732}', '\u{1734}', GC_Extend), ('\u{1752}', '\u{1753}',
+ GC_Extend), ('\u{1772}', '\u{1773}', GC_Extend), ('\u{17b4}', '\u{17b5}', GC_Extend),
+ ('\u{17b6}', '\u{17b6}', GC_SpacingMark), ('\u{17b7}', '\u{17bd}', GC_Extend), ('\u{17be}',
+ '\u{17c5}', GC_SpacingMark), ('\u{17c6}', '\u{17c6}', GC_Extend), ('\u{17c7}', '\u{17c8}',
+ GC_SpacingMark), ('\u{17c9}', '\u{17d3}', GC_Extend), ('\u{17dd}', '\u{17dd}', GC_Extend),
+ ('\u{180b}', '\u{180d}', GC_Extend), ('\u{180e}', '\u{180e}', GC_Control), ('\u{1885}',
+ '\u{1886}', GC_Extend), ('\u{18a9}', '\u{18a9}', GC_Extend), ('\u{1920}', '\u{1922}',
+ GC_Extend), ('\u{1923}', '\u{1926}', GC_SpacingMark), ('\u{1927}', '\u{1928}', GC_Extend),
+ ('\u{1929}', '\u{192b}', GC_SpacingMark), ('\u{1930}', '\u{1931}', GC_SpacingMark),
+ ('\u{1932}', '\u{1932}', GC_Extend), ('\u{1933}', '\u{1938}', GC_SpacingMark), ('\u{1939}',
+ '\u{193b}', GC_Extend), ('\u{1a17}', '\u{1a18}', GC_Extend), ('\u{1a19}', '\u{1a1a}',
+ GC_SpacingMark), ('\u{1a1b}', '\u{1a1b}', GC_Extend), ('\u{1a55}', '\u{1a55}',
+ GC_SpacingMark), ('\u{1a56}', '\u{1a56}', GC_Extend), ('\u{1a57}', '\u{1a57}',
+ GC_SpacingMark), ('\u{1a58}', '\u{1a5e}', GC_Extend), ('\u{1a60}', '\u{1a60}', GC_Extend),
+ ('\u{1a62}', '\u{1a62}', GC_Extend), ('\u{1a65}', '\u{1a6c}', GC_Extend), ('\u{1a6d}',
+ '\u{1a72}', GC_SpacingMark), ('\u{1a73}', '\u{1a7c}', GC_Extend), ('\u{1a7f}', '\u{1a7f}',
+ GC_Extend), ('\u{1ab0}', '\u{1abe}', GC_Extend), ('\u{1b00}', '\u{1b03}', GC_Extend),
+ ('\u{1b04}', '\u{1b04}', GC_SpacingMark), ('\u{1b34}', '\u{1b3a}', GC_Extend), ('\u{1b3b}',
+ '\u{1b3b}', GC_SpacingMark), ('\u{1b3c}', '\u{1b3c}', GC_Extend), ('\u{1b3d}', '\u{1b41}',
+ GC_SpacingMark), ('\u{1b42}', '\u{1b42}', GC_Extend), ('\u{1b43}', '\u{1b44}',
+ GC_SpacingMark), ('\u{1b6b}', '\u{1b73}', GC_Extend), ('\u{1b80}', '\u{1b81}', GC_Extend),
+ ('\u{1b82}', '\u{1b82}', GC_SpacingMark), ('\u{1ba1}', '\u{1ba1}', GC_SpacingMark),
+ ('\u{1ba2}', '\u{1ba5}', GC_Extend), ('\u{1ba6}', '\u{1ba7}', GC_SpacingMark), ('\u{1ba8}',
+ '\u{1ba9}', GC_Extend), ('\u{1baa}', '\u{1baa}', GC_SpacingMark), ('\u{1bab}', '\u{1bad}',
+ GC_Extend), ('\u{1be6}', '\u{1be6}', GC_Extend), ('\u{1be7}', '\u{1be7}', GC_SpacingMark),
+ ('\u{1be8}', '\u{1be9}', GC_Extend), ('\u{1bea}', '\u{1bec}', GC_SpacingMark), ('\u{1bed}',
+ '\u{1bed}', GC_Extend), ('\u{1bee}', '\u{1bee}', GC_SpacingMark), ('\u{1bef}', '\u{1bf1}',
+ GC_Extend), ('\u{1bf2}', '\u{1bf3}', GC_SpacingMark), ('\u{1c24}', '\u{1c2b}',
+ GC_SpacingMark), ('\u{1c2c}', '\u{1c33}', GC_Extend), ('\u{1c34}', '\u{1c35}',
+ GC_SpacingMark), ('\u{1c36}', '\u{1c37}', GC_Extend), ('\u{1cd0}', '\u{1cd2}', GC_Extend),
+ ('\u{1cd4}', '\u{1ce0}', GC_Extend), ('\u{1ce1}', '\u{1ce1}', GC_SpacingMark), ('\u{1ce2}',
+ '\u{1ce8}', GC_Extend), ('\u{1ced}', '\u{1ced}', GC_Extend), ('\u{1cf4}', '\u{1cf4}',
+ GC_Extend), ('\u{1cf7}', '\u{1cf7}', GC_SpacingMark), ('\u{1cf8}', '\u{1cf9}', GC_Extend),
+ ('\u{1dc0}', '\u{1df9}', GC_Extend), ('\u{1dfb}', '\u{1dff}', GC_Extend), ('\u{200b}',
+ '\u{200b}', GC_Control), ('\u{200c}', '\u{200c}', GC_Extend), ('\u{200d}', '\u{200d}',
+ GC_ZWJ), ('\u{200e}', '\u{200f}', GC_Control), ('\u{2028}', '\u{202e}', GC_Control),
+ ('\u{203c}', '\u{203c}', GC_Extended_Pictographic), ('\u{2049}', '\u{2049}',
+ GC_Extended_Pictographic), ('\u{2060}', '\u{206f}', GC_Control), ('\u{20d0}', '\u{20f0}',
+ GC_Extend), ('\u{2122}', '\u{2122}', GC_Extended_Pictographic), ('\u{2139}', '\u{2139}',
+ GC_Extended_Pictographic), ('\u{2194}', '\u{2199}', GC_Extended_Pictographic), ('\u{21a9}',
+ '\u{21aa}', GC_Extended_Pictographic), ('\u{231a}', '\u{231b}', GC_Extended_Pictographic),
+ ('\u{2328}', '\u{2328}', GC_Extended_Pictographic), ('\u{2388}', '\u{2388}',
+ GC_Extended_Pictographic), ('\u{23cf}', '\u{23cf}', GC_Extended_Pictographic), ('\u{23e9}',
+ '\u{23f3}', GC_Extended_Pictographic), ('\u{23f8}', '\u{23fa}', GC_Extended_Pictographic),
+ ('\u{24c2}', '\u{24c2}', GC_Extended_Pictographic), ('\u{25aa}', '\u{25ab}',
+ GC_Extended_Pictographic), ('\u{25b6}', '\u{25b6}', GC_Extended_Pictographic), ('\u{25c0}',
+ '\u{25c0}', GC_Extended_Pictographic), ('\u{25fb}', '\u{25fe}', GC_Extended_Pictographic),
+ ('\u{2600}', '\u{2605}', GC_Extended_Pictographic), ('\u{2607}', '\u{2612}',
+ GC_Extended_Pictographic), ('\u{2614}', '\u{2685}', GC_Extended_Pictographic), ('\u{2690}',
+ '\u{2705}', GC_Extended_Pictographic), ('\u{2708}', '\u{2712}', GC_Extended_Pictographic),
+ ('\u{2714}', '\u{2714}', GC_Extended_Pictographic), ('\u{2716}', '\u{2716}',
+ GC_Extended_Pictographic), ('\u{271d}', '\u{271d}', GC_Extended_Pictographic), ('\u{2721}',
+ '\u{2721}', GC_Extended_Pictographic), ('\u{2728}', '\u{2728}', GC_Extended_Pictographic),
+ ('\u{2733}', '\u{2734}', GC_Extended_Pictographic), ('\u{2744}', '\u{2744}',
+ GC_Extended_Pictographic), ('\u{2747}', '\u{2747}', GC_Extended_Pictographic), ('\u{274c}',
+ '\u{274c}', GC_Extended_Pictographic), ('\u{274e}', '\u{274e}', GC_Extended_Pictographic),
+ ('\u{2753}', '\u{2755}', GC_Extended_Pictographic), ('\u{2757}', '\u{2757}',
+ GC_Extended_Pictographic), ('\u{2763}', '\u{2767}', GC_Extended_Pictographic), ('\u{2795}',
+ '\u{2797}', GC_Extended_Pictographic), ('\u{27a1}', '\u{27a1}', GC_Extended_Pictographic),
+ ('\u{27b0}', '\u{27b0}', GC_Extended_Pictographic), ('\u{27bf}', '\u{27bf}',
+ GC_Extended_Pictographic), ('\u{2934}', '\u{2935}', GC_Extended_Pictographic), ('\u{2b05}',
+ '\u{2b07}', GC_Extended_Pictographic), ('\u{2b1b}', '\u{2b1c}', GC_Extended_Pictographic),
+ ('\u{2b50}', '\u{2b50}', GC_Extended_Pictographic), ('\u{2b55}', '\u{2b55}',
+ GC_Extended_Pictographic), ('\u{2cef}', '\u{2cf1}', GC_Extend), ('\u{2d7f}', '\u{2d7f}',
+ GC_Extend), ('\u{2de0}', '\u{2dff}', GC_Extend), ('\u{302a}', '\u{302f}', GC_Extend),
+ ('\u{3030}', '\u{3030}', GC_Extended_Pictographic), ('\u{303d}', '\u{303d}',
+ GC_Extended_Pictographic), ('\u{3099}', '\u{309a}', GC_Extend), ('\u{3297}', '\u{3297}',
+ GC_Extended_Pictographic), ('\u{3299}', '\u{3299}', GC_Extended_Pictographic), ('\u{a66f}',
+ '\u{a672}', GC_Extend), ('\u{a674}', '\u{a67d}', GC_Extend), ('\u{a69e}', '\u{a69f}',
+ GC_Extend), ('\u{a6f0}', '\u{a6f1}', GC_Extend), ('\u{a802}', '\u{a802}', GC_Extend),
+ ('\u{a806}', '\u{a806}', GC_Extend), ('\u{a80b}', '\u{a80b}', GC_Extend), ('\u{a823}',
+ '\u{a824}', GC_SpacingMark), ('\u{a825}', '\u{a826}', GC_Extend), ('\u{a827}', '\u{a827}',
+ GC_SpacingMark), ('\u{a880}', '\u{a881}', GC_SpacingMark), ('\u{a8b4}', '\u{a8c3}',
+ GC_SpacingMark), ('\u{a8c4}', '\u{a8c5}', GC_Extend), ('\u{a8e0}', '\u{a8f1}', GC_Extend),
+ ('\u{a8ff}', '\u{a8ff}', GC_Extend), ('\u{a926}', '\u{a92d}', GC_Extend), ('\u{a947}',
+ '\u{a951}', GC_Extend), ('\u{a952}', '\u{a953}', GC_SpacingMark), ('\u{a960}', '\u{a97c}',
+ GC_L), ('\u{a980}', '\u{a982}', GC_Extend), ('\u{a983}', '\u{a983}', GC_SpacingMark),
+ ('\u{a9b3}', '\u{a9b3}', GC_Extend), ('\u{a9b4}', '\u{a9b5}', GC_SpacingMark), ('\u{a9b6}',
+ '\u{a9b9}', GC_Extend), ('\u{a9ba}', '\u{a9bb}', GC_SpacingMark), ('\u{a9bc}', '\u{a9bd}',
+ GC_Extend), ('\u{a9be}', '\u{a9c0}', GC_SpacingMark), ('\u{a9e5}', '\u{a9e5}', GC_Extend),
+ ('\u{aa29}', '\u{aa2e}', GC_Extend), ('\u{aa2f}', '\u{aa30}', GC_SpacingMark), ('\u{aa31}',
+ '\u{aa32}', GC_Extend), ('\u{aa33}', '\u{aa34}', GC_SpacingMark), ('\u{aa35}', '\u{aa36}',
+ GC_Extend), ('\u{aa43}', '\u{aa43}', GC_Extend), ('\u{aa4c}', '\u{aa4c}', GC_Extend),
+ ('\u{aa4d}', '\u{aa4d}', GC_SpacingMark), ('\u{aa7c}', '\u{aa7c}', GC_Extend), ('\u{aab0}',
+ '\u{aab0}', GC_Extend), ('\u{aab2}', '\u{aab4}', GC_Extend), ('\u{aab7}', '\u{aab8}',
+ GC_Extend), ('\u{aabe}', '\u{aabf}', GC_Extend), ('\u{aac1}', '\u{aac1}', GC_Extend),
+ ('\u{aaeb}', '\u{aaeb}', GC_SpacingMark), ('\u{aaec}', '\u{aaed}', GC_Extend), ('\u{aaee}',
+ '\u{aaef}', GC_SpacingMark), ('\u{aaf5}', '\u{aaf5}', GC_SpacingMark), ('\u{aaf6}',
+ '\u{aaf6}', GC_Extend), ('\u{abe3}', '\u{abe4}', GC_SpacingMark), ('\u{abe5}', '\u{abe5}',
+ GC_Extend), ('\u{abe6}', '\u{abe7}', GC_SpacingMark), ('\u{abe8}', '\u{abe8}', GC_Extend),
+ ('\u{abe9}', '\u{abea}', GC_SpacingMark), ('\u{abec}', '\u{abec}', GC_SpacingMark),
+ ('\u{abed}', '\u{abed}', GC_Extend), ('\u{ac00}', '\u{ac00}', GC_LV), ('\u{ac01}',
+ '\u{ac1b}', GC_LVT), ('\u{ac1c}', '\u{ac1c}', GC_LV), ('\u{ac1d}', '\u{ac37}', GC_LVT),
+ ('\u{ac38}', '\u{ac38}', GC_LV), ('\u{ac39}', '\u{ac53}', GC_LVT), ('\u{ac54}', '\u{ac54}',
+ GC_LV), ('\u{ac55}', '\u{ac6f}', GC_LVT), ('\u{ac70}', '\u{ac70}', GC_LV), ('\u{ac71}',
+ '\u{ac8b}', GC_LVT), ('\u{ac8c}', '\u{ac8c}', GC_LV), ('\u{ac8d}', '\u{aca7}', GC_LVT),
+ ('\u{aca8}', '\u{aca8}', GC_LV), ('\u{aca9}', '\u{acc3}', GC_LVT), ('\u{acc4}', '\u{acc4}',
+ GC_LV), ('\u{acc5}', '\u{acdf}', GC_LVT), ('\u{ace0}', '\u{ace0}', GC_LV), ('\u{ace1}',
+ '\u{acfb}', GC_LVT), ('\u{acfc}', '\u{acfc}', GC_LV), ('\u{acfd}', '\u{ad17}', GC_LVT),
+ ('\u{ad18}', '\u{ad18}', GC_LV), ('\u{ad19}', '\u{ad33}', GC_LVT), ('\u{ad34}', '\u{ad34}',
+ GC_LV), ('\u{ad35}', '\u{ad4f}', GC_LVT), ('\u{ad50}', '\u{ad50}', GC_LV), ('\u{ad51}',
+ '\u{ad6b}', GC_LVT), ('\u{ad6c}', '\u{ad6c}', GC_LV), ('\u{ad6d}', '\u{ad87}', GC_LVT),
+ ('\u{ad88}', '\u{ad88}', GC_LV), ('\u{ad89}', '\u{ada3}', GC_LVT), ('\u{ada4}', '\u{ada4}',
+ GC_LV), ('\u{ada5}', '\u{adbf}', GC_LVT), ('\u{adc0}', '\u{adc0}', GC_LV), ('\u{adc1}',
+ '\u{addb}', GC_LVT), ('\u{addc}', '\u{addc}', GC_LV), ('\u{addd}', '\u{adf7}', GC_LVT),
+ ('\u{adf8}', '\u{adf8}', GC_LV), ('\u{adf9}', '\u{ae13}', GC_LVT), ('\u{ae14}', '\u{ae14}',
+ GC_LV), ('\u{ae15}', '\u{ae2f}', GC_LVT), ('\u{ae30}', '\u{ae30}', GC_LV), ('\u{ae31}',
+ '\u{ae4b}', GC_LVT), ('\u{ae4c}', '\u{ae4c}', GC_LV), ('\u{ae4d}', '\u{ae67}', GC_LVT),
+ ('\u{ae68}', '\u{ae68}', GC_LV), ('\u{ae69}', '\u{ae83}', GC_LVT), ('\u{ae84}', '\u{ae84}',
+ GC_LV), ('\u{ae85}', '\u{ae9f}', GC_LVT), ('\u{aea0}', '\u{aea0}', GC_LV), ('\u{aea1}',
+ '\u{aebb}', GC_LVT), ('\u{aebc}', '\u{aebc}', GC_LV), ('\u{aebd}', '\u{aed7}', GC_LVT),
+ ('\u{aed8}', '\u{aed8}', GC_LV), ('\u{aed9}', '\u{aef3}', GC_LVT), ('\u{aef4}', '\u{aef4}',
+ GC_LV), ('\u{aef5}', '\u{af0f}', GC_LVT), ('\u{af10}', '\u{af10}', GC_LV), ('\u{af11}',
+ '\u{af2b}', GC_LVT), ('\u{af2c}', '\u{af2c}', GC_LV), ('\u{af2d}', '\u{af47}', GC_LVT),
+ ('\u{af48}', '\u{af48}', GC_LV), ('\u{af49}', '\u{af63}', GC_LVT), ('\u{af64}', '\u{af64}',
+ GC_LV), ('\u{af65}', '\u{af7f}', GC_LVT), ('\u{af80}', '\u{af80}', GC_LV), ('\u{af81}',
+ '\u{af9b}', GC_LVT), ('\u{af9c}', '\u{af9c}', GC_LV), ('\u{af9d}', '\u{afb7}', GC_LVT),
+ ('\u{afb8}', '\u{afb8}', GC_LV), ('\u{afb9}', '\u{afd3}', GC_LVT), ('\u{afd4}', '\u{afd4}',
+ GC_LV), ('\u{afd5}', '\u{afef}', GC_LVT), ('\u{aff0}', '\u{aff0}', GC_LV), ('\u{aff1}',
+ '\u{b00b}', GC_LVT), ('\u{b00c}', '\u{b00c}', GC_LV), ('\u{b00d}', '\u{b027}', GC_LVT),
+ ('\u{b028}', '\u{b028}', GC_LV), ('\u{b029}', '\u{b043}', GC_LVT), ('\u{b044}', '\u{b044}',
+ GC_LV), ('\u{b045}', '\u{b05f}', GC_LVT), ('\u{b060}', '\u{b060}', GC_LV), ('\u{b061}',
+ '\u{b07b}', GC_LVT), ('\u{b07c}', '\u{b07c}', GC_LV), ('\u{b07d}', '\u{b097}', GC_LVT),
+ ('\u{b098}', '\u{b098}', GC_LV), ('\u{b099}', '\u{b0b3}', GC_LVT), ('\u{b0b4}', '\u{b0b4}',
+ GC_LV), ('\u{b0b5}', '\u{b0cf}', GC_LVT), ('\u{b0d0}', '\u{b0d0}', GC_LV), ('\u{b0d1}',
+ '\u{b0eb}', GC_LVT), ('\u{b0ec}', '\u{b0ec}', GC_LV), ('\u{b0ed}', '\u{b107}', GC_LVT),
+ ('\u{b108}', '\u{b108}', GC_LV), ('\u{b109}', '\u{b123}', GC_LVT), ('\u{b124}', '\u{b124}',
+ GC_LV), ('\u{b125}', '\u{b13f}', GC_LVT), ('\u{b140}', '\u{b140}', GC_LV), ('\u{b141}',
+ '\u{b15b}', GC_LVT), ('\u{b15c}', '\u{b15c}', GC_LV), ('\u{b15d}', '\u{b177}', GC_LVT),
+ ('\u{b178}', '\u{b178}', GC_LV), ('\u{b179}', '\u{b193}', GC_LVT), ('\u{b194}', '\u{b194}',
+ GC_LV), ('\u{b195}', '\u{b1af}', GC_LVT), ('\u{b1b0}', '\u{b1b0}', GC_LV), ('\u{b1b1}',
+ '\u{b1cb}', GC_LVT), ('\u{b1cc}', '\u{b1cc}', GC_LV), ('\u{b1cd}', '\u{b1e7}', GC_LVT),
+ ('\u{b1e8}', '\u{b1e8}', GC_LV), ('\u{b1e9}', '\u{b203}', GC_LVT), ('\u{b204}', '\u{b204}',
+ GC_LV), ('\u{b205}', '\u{b21f}', GC_LVT), ('\u{b220}', '\u{b220}', GC_LV), ('\u{b221}',
+ '\u{b23b}', GC_LVT), ('\u{b23c}', '\u{b23c}', GC_LV), ('\u{b23d}', '\u{b257}', GC_LVT),
+ ('\u{b258}', '\u{b258}', GC_LV), ('\u{b259}', '\u{b273}', GC_LVT), ('\u{b274}', '\u{b274}',
+ GC_LV), ('\u{b275}', '\u{b28f}', GC_LVT), ('\u{b290}', '\u{b290}', GC_LV), ('\u{b291}',
+ '\u{b2ab}', GC_LVT), ('\u{b2ac}', '\u{b2ac}', GC_LV), ('\u{b2ad}', '\u{b2c7}', GC_LVT),
+ ('\u{b2c8}', '\u{b2c8}', GC_LV), ('\u{b2c9}', '\u{b2e3}', GC_LVT), ('\u{b2e4}', '\u{b2e4}',
+ GC_LV), ('\u{b2e5}', '\u{b2ff}', GC_LVT), ('\u{b300}', '\u{b300}', GC_LV), ('\u{b301}',
+ '\u{b31b}', GC_LVT), ('\u{b31c}', '\u{b31c}', GC_LV), ('\u{b31d}', '\u{b337}', GC_LVT),
+ ('\u{b338}', '\u{b338}', GC_LV), ('\u{b339}', '\u{b353}', GC_LVT), ('\u{b354}', '\u{b354}',
+ GC_LV), ('\u{b355}', '\u{b36f}', GC_LVT), ('\u{b370}', '\u{b370}', GC_LV), ('\u{b371}',
+ '\u{b38b}', GC_LVT), ('\u{b38c}', '\u{b38c}', GC_LV), ('\u{b38d}', '\u{b3a7}', GC_LVT),
+ ('\u{b3a8}', '\u{b3a8}', GC_LV), ('\u{b3a9}', '\u{b3c3}', GC_LVT), ('\u{b3c4}', '\u{b3c4}',
+ GC_LV), ('\u{b3c5}', '\u{b3df}', GC_LVT), ('\u{b3e0}', '\u{b3e0}', GC_LV), ('\u{b3e1}',
+ '\u{b3fb}', GC_LVT), ('\u{b3fc}', '\u{b3fc}', GC_LV), ('\u{b3fd}', '\u{b417}', GC_LVT),
+ ('\u{b418}', '\u{b418}', GC_LV), ('\u{b419}', '\u{b433}', GC_LVT), ('\u{b434}', '\u{b434}',
+ GC_LV), ('\u{b435}', '\u{b44f}', GC_LVT), ('\u{b450}', '\u{b450}', GC_LV), ('\u{b451}',
+ '\u{b46b}', GC_LVT), ('\u{b46c}', '\u{b46c}', GC_LV), ('\u{b46d}', '\u{b487}', GC_LVT),
+ ('\u{b488}', '\u{b488}', GC_LV), ('\u{b489}', '\u{b4a3}', GC_LVT), ('\u{b4a4}', '\u{b4a4}',
+ GC_LV), ('\u{b4a5}', '\u{b4bf}', GC_LVT), ('\u{b4c0}', '\u{b4c0}', GC_LV), ('\u{b4c1}',
+ '\u{b4db}', GC_LVT), ('\u{b4dc}', '\u{b4dc}', GC_LV), ('\u{b4dd}', '\u{b4f7}', GC_LVT),
+ ('\u{b4f8}', '\u{b4f8}', GC_LV), ('\u{b4f9}', '\u{b513}', GC_LVT), ('\u{b514}', '\u{b514}',
+ GC_LV), ('\u{b515}', '\u{b52f}', GC_LVT), ('\u{b530}', '\u{b530}', GC_LV), ('\u{b531}',
+ '\u{b54b}', GC_LVT), ('\u{b54c}', '\u{b54c}', GC_LV), ('\u{b54d}', '\u{b567}', GC_LVT),
+ ('\u{b568}', '\u{b568}', GC_LV), ('\u{b569}', '\u{b583}', GC_LVT), ('\u{b584}', '\u{b584}',
+ GC_LV), ('\u{b585}', '\u{b59f}', GC_LVT), ('\u{b5a0}', '\u{b5a0}', GC_LV), ('\u{b5a1}',
+ '\u{b5bb}', GC_LVT), ('\u{b5bc}', '\u{b5bc}', GC_LV), ('\u{b5bd}', '\u{b5d7}', GC_LVT),
+ ('\u{b5d8}', '\u{b5d8}', GC_LV), ('\u{b5d9}', '\u{b5f3}', GC_LVT), ('\u{b5f4}', '\u{b5f4}',
+ GC_LV), ('\u{b5f5}', '\u{b60f}', GC_LVT), ('\u{b610}', '\u{b610}', GC_LV), ('\u{b611}',
+ '\u{b62b}', GC_LVT), ('\u{b62c}', '\u{b62c}', GC_LV), ('\u{b62d}', '\u{b647}', GC_LVT),
+ ('\u{b648}', '\u{b648}', GC_LV), ('\u{b649}', '\u{b663}', GC_LVT), ('\u{b664}', '\u{b664}',
+ GC_LV), ('\u{b665}', '\u{b67f}', GC_LVT), ('\u{b680}', '\u{b680}', GC_LV), ('\u{b681}',
+ '\u{b69b}', GC_LVT), ('\u{b69c}', '\u{b69c}', GC_LV), ('\u{b69d}', '\u{b6b7}', GC_LVT),
+ ('\u{b6b8}', '\u{b6b8}', GC_LV), ('\u{b6b9}', '\u{b6d3}', GC_LVT), ('\u{b6d4}', '\u{b6d4}',
+ GC_LV), ('\u{b6d5}', '\u{b6ef}', GC_LVT), ('\u{b6f0}', '\u{b6f0}', GC_LV), ('\u{b6f1}',
+ '\u{b70b}', GC_LVT), ('\u{b70c}', '\u{b70c}', GC_LV), ('\u{b70d}', '\u{b727}', GC_LVT),
+ ('\u{b728}', '\u{b728}', GC_LV), ('\u{b729}', '\u{b743}', GC_LVT), ('\u{b744}', '\u{b744}',
+ GC_LV), ('\u{b745}', '\u{b75f}', GC_LVT), ('\u{b760}', '\u{b760}', GC_LV), ('\u{b761}',
+ '\u{b77b}', GC_LVT), ('\u{b77c}', '\u{b77c}', GC_LV), ('\u{b77d}', '\u{b797}', GC_LVT),
+ ('\u{b798}', '\u{b798}', GC_LV), ('\u{b799}', '\u{b7b3}', GC_LVT), ('\u{b7b4}', '\u{b7b4}',
+ GC_LV), ('\u{b7b5}', '\u{b7cf}', GC_LVT), ('\u{b7d0}', '\u{b7d0}', GC_LV), ('\u{b7d1}',
+ '\u{b7eb}', GC_LVT), ('\u{b7ec}', '\u{b7ec}', GC_LV), ('\u{b7ed}', '\u{b807}', GC_LVT),
+ ('\u{b808}', '\u{b808}', GC_LV), ('\u{b809}', '\u{b823}', GC_LVT), ('\u{b824}', '\u{b824}',
+ GC_LV), ('\u{b825}', '\u{b83f}', GC_LVT), ('\u{b840}', '\u{b840}', GC_LV), ('\u{b841}',
+ '\u{b85b}', GC_LVT), ('\u{b85c}', '\u{b85c}', GC_LV), ('\u{b85d}', '\u{b877}', GC_LVT),
+ ('\u{b878}', '\u{b878}', GC_LV), ('\u{b879}', '\u{b893}', GC_LVT), ('\u{b894}', '\u{b894}',
+ GC_LV), ('\u{b895}', '\u{b8af}', GC_LVT), ('\u{b8b0}', '\u{b8b0}', GC_LV), ('\u{b8b1}',
+ '\u{b8cb}', GC_LVT), ('\u{b8cc}', '\u{b8cc}', GC_LV), ('\u{b8cd}', '\u{b8e7}', GC_LVT),
+ ('\u{b8e8}', '\u{b8e8}', GC_LV), ('\u{b8e9}', '\u{b903}', GC_LVT), ('\u{b904}', '\u{b904}',
+ GC_LV), ('\u{b905}', '\u{b91f}', GC_LVT), ('\u{b920}', '\u{b920}', GC_LV), ('\u{b921}',
+ '\u{b93b}', GC_LVT), ('\u{b93c}', '\u{b93c}', GC_LV), ('\u{b93d}', '\u{b957}', GC_LVT),
+ ('\u{b958}', '\u{b958}', GC_LV), ('\u{b959}', '\u{b973}', GC_LVT), ('\u{b974}', '\u{b974}',
+ GC_LV), ('\u{b975}', '\u{b98f}', GC_LVT), ('\u{b990}', '\u{b990}', GC_LV), ('\u{b991}',
+ '\u{b9ab}', GC_LVT), ('\u{b9ac}', '\u{b9ac}', GC_LV), ('\u{b9ad}', '\u{b9c7}', GC_LVT),
+ ('\u{b9c8}', '\u{b9c8}', GC_LV), ('\u{b9c9}', '\u{b9e3}', GC_LVT), ('\u{b9e4}', '\u{b9e4}',
+ GC_LV), ('\u{b9e5}', '\u{b9ff}', GC_LVT), ('\u{ba00}', '\u{ba00}', GC_LV), ('\u{ba01}',
+ '\u{ba1b}', GC_LVT), ('\u{ba1c}', '\u{ba1c}', GC_LV), ('\u{ba1d}', '\u{ba37}', GC_LVT),
+ ('\u{ba38}', '\u{ba38}', GC_LV), ('\u{ba39}', '\u{ba53}', GC_LVT), ('\u{ba54}', '\u{ba54}',
+ GC_LV), ('\u{ba55}', '\u{ba6f}', GC_LVT), ('\u{ba70}', '\u{ba70}', GC_LV), ('\u{ba71}',
+ '\u{ba8b}', GC_LVT), ('\u{ba8c}', '\u{ba8c}', GC_LV), ('\u{ba8d}', '\u{baa7}', GC_LVT),
+ ('\u{baa8}', '\u{baa8}', GC_LV), ('\u{baa9}', '\u{bac3}', GC_LVT), ('\u{bac4}', '\u{bac4}',
+ GC_LV), ('\u{bac5}', '\u{badf}', GC_LVT), ('\u{bae0}', '\u{bae0}', GC_LV), ('\u{bae1}',
+ '\u{bafb}', GC_LVT), ('\u{bafc}', '\u{bafc}', GC_LV), ('\u{bafd}', '\u{bb17}', GC_LVT),
+ ('\u{bb18}', '\u{bb18}', GC_LV), ('\u{bb19}', '\u{bb33}', GC_LVT), ('\u{bb34}', '\u{bb34}',
+ GC_LV), ('\u{bb35}', '\u{bb4f}', GC_LVT), ('\u{bb50}', '\u{bb50}', GC_LV), ('\u{bb51}',
+ '\u{bb6b}', GC_LVT), ('\u{bb6c}', '\u{bb6c}', GC_LV), ('\u{bb6d}', '\u{bb87}', GC_LVT),
+ ('\u{bb88}', '\u{bb88}', GC_LV), ('\u{bb89}', '\u{bba3}', GC_LVT), ('\u{bba4}', '\u{bba4}',
+ GC_LV), ('\u{bba5}', '\u{bbbf}', GC_LVT), ('\u{bbc0}', '\u{bbc0}', GC_LV), ('\u{bbc1}',
+ '\u{bbdb}', GC_LVT), ('\u{bbdc}', '\u{bbdc}', GC_LV), ('\u{bbdd}', '\u{bbf7}', GC_LVT),
+ ('\u{bbf8}', '\u{bbf8}', GC_LV), ('\u{bbf9}', '\u{bc13}', GC_LVT), ('\u{bc14}', '\u{bc14}',
+ GC_LV), ('\u{bc15}', '\u{bc2f}', GC_LVT), ('\u{bc30}', '\u{bc30}', GC_LV), ('\u{bc31}',
+ '\u{bc4b}', GC_LVT), ('\u{bc4c}', '\u{bc4c}', GC_LV), ('\u{bc4d}', '\u{bc67}', GC_LVT),
+ ('\u{bc68}', '\u{bc68}', GC_LV), ('\u{bc69}', '\u{bc83}', GC_LVT), ('\u{bc84}', '\u{bc84}',
+ GC_LV), ('\u{bc85}', '\u{bc9f}', GC_LVT), ('\u{bca0}', '\u{bca0}', GC_LV), ('\u{bca1}',
+ '\u{bcbb}', GC_LVT), ('\u{bcbc}', '\u{bcbc}', GC_LV), ('\u{bcbd}', '\u{bcd7}', GC_LVT),
+ ('\u{bcd8}', '\u{bcd8}', GC_LV), ('\u{bcd9}', '\u{bcf3}', GC_LVT), ('\u{bcf4}', '\u{bcf4}',
+ GC_LV), ('\u{bcf5}', '\u{bd0f}', GC_LVT), ('\u{bd10}', '\u{bd10}', GC_LV), ('\u{bd11}',
+ '\u{bd2b}', GC_LVT), ('\u{bd2c}', '\u{bd2c}', GC_LV), ('\u{bd2d}', '\u{bd47}', GC_LVT),
+ ('\u{bd48}', '\u{bd48}', GC_LV), ('\u{bd49}', '\u{bd63}', GC_LVT), ('\u{bd64}', '\u{bd64}',
+ GC_LV), ('\u{bd65}', '\u{bd7f}', GC_LVT), ('\u{bd80}', '\u{bd80}', GC_LV), ('\u{bd81}',
+ '\u{bd9b}', GC_LVT), ('\u{bd9c}', '\u{bd9c}', GC_LV), ('\u{bd9d}', '\u{bdb7}', GC_LVT),
+ ('\u{bdb8}', '\u{bdb8}', GC_LV), ('\u{bdb9}', '\u{bdd3}', GC_LVT), ('\u{bdd4}', '\u{bdd4}',
+ GC_LV), ('\u{bdd5}', '\u{bdef}', GC_LVT), ('\u{bdf0}', '\u{bdf0}', GC_LV), ('\u{bdf1}',
+ '\u{be0b}', GC_LVT), ('\u{be0c}', '\u{be0c}', GC_LV), ('\u{be0d}', '\u{be27}', GC_LVT),
+ ('\u{be28}', '\u{be28}', GC_LV), ('\u{be29}', '\u{be43}', GC_LVT), ('\u{be44}', '\u{be44}',
+ GC_LV), ('\u{be45}', '\u{be5f}', GC_LVT), ('\u{be60}', '\u{be60}', GC_LV), ('\u{be61}',
+ '\u{be7b}', GC_LVT), ('\u{be7c}', '\u{be7c}', GC_LV), ('\u{be7d}', '\u{be97}', GC_LVT),
+ ('\u{be98}', '\u{be98}', GC_LV), ('\u{be99}', '\u{beb3}', GC_LVT), ('\u{beb4}', '\u{beb4}',
+ GC_LV), ('\u{beb5}', '\u{becf}', GC_LVT), ('\u{bed0}', '\u{bed0}', GC_LV), ('\u{bed1}',
+ '\u{beeb}', GC_LVT), ('\u{beec}', '\u{beec}', GC_LV), ('\u{beed}', '\u{bf07}', GC_LVT),
+ ('\u{bf08}', '\u{bf08}', GC_LV), ('\u{bf09}', '\u{bf23}', GC_LVT), ('\u{bf24}', '\u{bf24}',
+ GC_LV), ('\u{bf25}', '\u{bf3f}', GC_LVT), ('\u{bf40}', '\u{bf40}', GC_LV), ('\u{bf41}',
+ '\u{bf5b}', GC_LVT), ('\u{bf5c}', '\u{bf5c}', GC_LV), ('\u{bf5d}', '\u{bf77}', GC_LVT),
+ ('\u{bf78}', '\u{bf78}', GC_LV), ('\u{bf79}', '\u{bf93}', GC_LVT), ('\u{bf94}', '\u{bf94}',
+ GC_LV), ('\u{bf95}', '\u{bfaf}', GC_LVT), ('\u{bfb0}', '\u{bfb0}', GC_LV), ('\u{bfb1}',
+ '\u{bfcb}', GC_LVT), ('\u{bfcc}', '\u{bfcc}', GC_LV), ('\u{bfcd}', '\u{bfe7}', GC_LVT),
+ ('\u{bfe8}', '\u{bfe8}', GC_LV), ('\u{bfe9}', '\u{c003}', GC_LVT), ('\u{c004}', '\u{c004}',
+ GC_LV), ('\u{c005}', '\u{c01f}', GC_LVT), ('\u{c020}', '\u{c020}', GC_LV), ('\u{c021}',
+ '\u{c03b}', GC_LVT), ('\u{c03c}', '\u{c03c}', GC_LV), ('\u{c03d}', '\u{c057}', GC_LVT),
+ ('\u{c058}', '\u{c058}', GC_LV), ('\u{c059}', '\u{c073}', GC_LVT), ('\u{c074}', '\u{c074}',
+ GC_LV), ('\u{c075}', '\u{c08f}', GC_LVT), ('\u{c090}', '\u{c090}', GC_LV), ('\u{c091}',
+ '\u{c0ab}', GC_LVT), ('\u{c0ac}', '\u{c0ac}', GC_LV), ('\u{c0ad}', '\u{c0c7}', GC_LVT),
+ ('\u{c0c8}', '\u{c0c8}', GC_LV), ('\u{c0c9}', '\u{c0e3}', GC_LVT), ('\u{c0e4}', '\u{c0e4}',
+ GC_LV), ('\u{c0e5}', '\u{c0ff}', GC_LVT), ('\u{c100}', '\u{c100}', GC_LV), ('\u{c101}',
+ '\u{c11b}', GC_LVT), ('\u{c11c}', '\u{c11c}', GC_LV), ('\u{c11d}', '\u{c137}', GC_LVT),
+ ('\u{c138}', '\u{c138}', GC_LV), ('\u{c139}', '\u{c153}', GC_LVT), ('\u{c154}', '\u{c154}',
+ GC_LV), ('\u{c155}', '\u{c16f}', GC_LVT), ('\u{c170}', '\u{c170}', GC_LV), ('\u{c171}',
+ '\u{c18b}', GC_LVT), ('\u{c18c}', '\u{c18c}', GC_LV), ('\u{c18d}', '\u{c1a7}', GC_LVT),
+ ('\u{c1a8}', '\u{c1a8}', GC_LV), ('\u{c1a9}', '\u{c1c3}', GC_LVT), ('\u{c1c4}', '\u{c1c4}',
+ GC_LV), ('\u{c1c5}', '\u{c1df}', GC_LVT), ('\u{c1e0}', '\u{c1e0}', GC_LV), ('\u{c1e1}',
+ '\u{c1fb}', GC_LVT), ('\u{c1fc}', '\u{c1fc}', GC_LV), ('\u{c1fd}', '\u{c217}', GC_LVT),
+ ('\u{c218}', '\u{c218}', GC_LV), ('\u{c219}', '\u{c233}', GC_LVT), ('\u{c234}', '\u{c234}',
+ GC_LV), ('\u{c235}', '\u{c24f}', GC_LVT), ('\u{c250}', '\u{c250}', GC_LV), ('\u{c251}',
+ '\u{c26b}', GC_LVT), ('\u{c26c}', '\u{c26c}', GC_LV), ('\u{c26d}', '\u{c287}', GC_LVT),
+ ('\u{c288}', '\u{c288}', GC_LV), ('\u{c289}', '\u{c2a3}', GC_LVT), ('\u{c2a4}', '\u{c2a4}',
+ GC_LV), ('\u{c2a5}', '\u{c2bf}', GC_LVT), ('\u{c2c0}', '\u{c2c0}', GC_LV), ('\u{c2c1}',
+ '\u{c2db}', GC_LVT), ('\u{c2dc}', '\u{c2dc}', GC_LV), ('\u{c2dd}', '\u{c2f7}', GC_LVT),
+ ('\u{c2f8}', '\u{c2f8}', GC_LV), ('\u{c2f9}', '\u{c313}', GC_LVT), ('\u{c314}', '\u{c314}',
+ GC_LV), ('\u{c315}', '\u{c32f}', GC_LVT), ('\u{c330}', '\u{c330}', GC_LV), ('\u{c331}',
+ '\u{c34b}', GC_LVT), ('\u{c34c}', '\u{c34c}', GC_LV), ('\u{c34d}', '\u{c367}', GC_LVT),
+ ('\u{c368}', '\u{c368}', GC_LV), ('\u{c369}', '\u{c383}', GC_LVT), ('\u{c384}', '\u{c384}',
+ GC_LV), ('\u{c385}', '\u{c39f}', GC_LVT), ('\u{c3a0}', '\u{c3a0}', GC_LV), ('\u{c3a1}',
+ '\u{c3bb}', GC_LVT), ('\u{c3bc}', '\u{c3bc}', GC_LV), ('\u{c3bd}', '\u{c3d7}', GC_LVT),
+ ('\u{c3d8}', '\u{c3d8}', GC_LV), ('\u{c3d9}', '\u{c3f3}', GC_LVT), ('\u{c3f4}', '\u{c3f4}',
+ GC_LV), ('\u{c3f5}', '\u{c40f}', GC_LVT), ('\u{c410}', '\u{c410}', GC_LV), ('\u{c411}',
+ '\u{c42b}', GC_LVT), ('\u{c42c}', '\u{c42c}', GC_LV), ('\u{c42d}', '\u{c447}', GC_LVT),
+ ('\u{c448}', '\u{c448}', GC_LV), ('\u{c449}', '\u{c463}', GC_LVT), ('\u{c464}', '\u{c464}',
+ GC_LV), ('\u{c465}', '\u{c47f}', GC_LVT), ('\u{c480}', '\u{c480}', GC_LV), ('\u{c481}',
+ '\u{c49b}', GC_LVT), ('\u{c49c}', '\u{c49c}', GC_LV), ('\u{c49d}', '\u{c4b7}', GC_LVT),
+ ('\u{c4b8}', '\u{c4b8}', GC_LV), ('\u{c4b9}', '\u{c4d3}', GC_LVT), ('\u{c4d4}', '\u{c4d4}',
+ GC_LV), ('\u{c4d5}', '\u{c4ef}', GC_LVT), ('\u{c4f0}', '\u{c4f0}', GC_LV), ('\u{c4f1}',
+ '\u{c50b}', GC_LVT), ('\u{c50c}', '\u{c50c}', GC_LV), ('\u{c50d}', '\u{c527}', GC_LVT),
+ ('\u{c528}', '\u{c528}', GC_LV), ('\u{c529}', '\u{c543}', GC_LVT), ('\u{c544}', '\u{c544}',
+ GC_LV), ('\u{c545}', '\u{c55f}', GC_LVT), ('\u{c560}', '\u{c560}', GC_LV), ('\u{c561}',
+ '\u{c57b}', GC_LVT), ('\u{c57c}', '\u{c57c}', GC_LV), ('\u{c57d}', '\u{c597}', GC_LVT),
+ ('\u{c598}', '\u{c598}', GC_LV), ('\u{c599}', '\u{c5b3}', GC_LVT), ('\u{c5b4}', '\u{c5b4}',
+ GC_LV), ('\u{c5b5}', '\u{c5cf}', GC_LVT), ('\u{c5d0}', '\u{c5d0}', GC_LV), ('\u{c5d1}',
+ '\u{c5eb}', GC_LVT), ('\u{c5ec}', '\u{c5ec}', GC_LV), ('\u{c5ed}', '\u{c607}', GC_LVT),
+ ('\u{c608}', '\u{c608}', GC_LV), ('\u{c609}', '\u{c623}', GC_LVT), ('\u{c624}', '\u{c624}',
+ GC_LV), ('\u{c625}', '\u{c63f}', GC_LVT), ('\u{c640}', '\u{c640}', GC_LV), ('\u{c641}',
+ '\u{c65b}', GC_LVT), ('\u{c65c}', '\u{c65c}', GC_LV), ('\u{c65d}', '\u{c677}', GC_LVT),
+ ('\u{c678}', '\u{c678}', GC_LV), ('\u{c679}', '\u{c693}', GC_LVT), ('\u{c694}', '\u{c694}',
+ GC_LV), ('\u{c695}', '\u{c6af}', GC_LVT), ('\u{c6b0}', '\u{c6b0}', GC_LV), ('\u{c6b1}',
+ '\u{c6cb}', GC_LVT), ('\u{c6cc}', '\u{c6cc}', GC_LV), ('\u{c6cd}', '\u{c6e7}', GC_LVT),
+ ('\u{c6e8}', '\u{c6e8}', GC_LV), ('\u{c6e9}', '\u{c703}', GC_LVT), ('\u{c704}', '\u{c704}',
+ GC_LV), ('\u{c705}', '\u{c71f}', GC_LVT), ('\u{c720}', '\u{c720}', GC_LV), ('\u{c721}',
+ '\u{c73b}', GC_LVT), ('\u{c73c}', '\u{c73c}', GC_LV), ('\u{c73d}', '\u{c757}', GC_LVT),
+ ('\u{c758}', '\u{c758}', GC_LV), ('\u{c759}', '\u{c773}', GC_LVT), ('\u{c774}', '\u{c774}',
+ GC_LV), ('\u{c775}', '\u{c78f}', GC_LVT), ('\u{c790}', '\u{c790}', GC_LV), ('\u{c791}',
+ '\u{c7ab}', GC_LVT), ('\u{c7ac}', '\u{c7ac}', GC_LV), ('\u{c7ad}', '\u{c7c7}', GC_LVT),
+ ('\u{c7c8}', '\u{c7c8}', GC_LV), ('\u{c7c9}', '\u{c7e3}', GC_LVT), ('\u{c7e4}', '\u{c7e4}',
+ GC_LV), ('\u{c7e5}', '\u{c7ff}', GC_LVT), ('\u{c800}', '\u{c800}', GC_LV), ('\u{c801}',
+ '\u{c81b}', GC_LVT), ('\u{c81c}', '\u{c81c}', GC_LV), ('\u{c81d}', '\u{c837}', GC_LVT),
+ ('\u{c838}', '\u{c838}', GC_LV), ('\u{c839}', '\u{c853}', GC_LVT), ('\u{c854}', '\u{c854}',
+ GC_LV), ('\u{c855}', '\u{c86f}', GC_LVT), ('\u{c870}', '\u{c870}', GC_LV), ('\u{c871}',
+ '\u{c88b}', GC_LVT), ('\u{c88c}', '\u{c88c}', GC_LV), ('\u{c88d}', '\u{c8a7}', GC_LVT),
+ ('\u{c8a8}', '\u{c8a8}', GC_LV), ('\u{c8a9}', '\u{c8c3}', GC_LVT), ('\u{c8c4}', '\u{c8c4}',
+ GC_LV), ('\u{c8c5}', '\u{c8df}', GC_LVT), ('\u{c8e0}', '\u{c8e0}', GC_LV), ('\u{c8e1}',
+ '\u{c8fb}', GC_LVT), ('\u{c8fc}', '\u{c8fc}', GC_LV), ('\u{c8fd}', '\u{c917}', GC_LVT),
+ ('\u{c918}', '\u{c918}', GC_LV), ('\u{c919}', '\u{c933}', GC_LVT), ('\u{c934}', '\u{c934}',
+ GC_LV), ('\u{c935}', '\u{c94f}', GC_LVT), ('\u{c950}', '\u{c950}', GC_LV), ('\u{c951}',
+ '\u{c96b}', GC_LVT), ('\u{c96c}', '\u{c96c}', GC_LV), ('\u{c96d}', '\u{c987}', GC_LVT),
+ ('\u{c988}', '\u{c988}', GC_LV), ('\u{c989}', '\u{c9a3}', GC_LVT), ('\u{c9a4}', '\u{c9a4}',
+ GC_LV), ('\u{c9a5}', '\u{c9bf}', GC_LVT), ('\u{c9c0}', '\u{c9c0}', GC_LV), ('\u{c9c1}',
+ '\u{c9db}', GC_LVT), ('\u{c9dc}', '\u{c9dc}', GC_LV), ('\u{c9dd}', '\u{c9f7}', GC_LVT),
+ ('\u{c9f8}', '\u{c9f8}', GC_LV), ('\u{c9f9}', '\u{ca13}', GC_LVT), ('\u{ca14}', '\u{ca14}',
+ GC_LV), ('\u{ca15}', '\u{ca2f}', GC_LVT), ('\u{ca30}', '\u{ca30}', GC_LV), ('\u{ca31}',
+ '\u{ca4b}', GC_LVT), ('\u{ca4c}', '\u{ca4c}', GC_LV), ('\u{ca4d}', '\u{ca67}', GC_LVT),
+ ('\u{ca68}', '\u{ca68}', GC_LV), ('\u{ca69}', '\u{ca83}', GC_LVT), ('\u{ca84}', '\u{ca84}',
+ GC_LV), ('\u{ca85}', '\u{ca9f}', GC_LVT), ('\u{caa0}', '\u{caa0}', GC_LV), ('\u{caa1}',
+ '\u{cabb}', GC_LVT), ('\u{cabc}', '\u{cabc}', GC_LV), ('\u{cabd}', '\u{cad7}', GC_LVT),
+ ('\u{cad8}', '\u{cad8}', GC_LV), ('\u{cad9}', '\u{caf3}', GC_LVT), ('\u{caf4}', '\u{caf4}',
+ GC_LV), ('\u{caf5}', '\u{cb0f}', GC_LVT), ('\u{cb10}', '\u{cb10}', GC_LV), ('\u{cb11}',
+ '\u{cb2b}', GC_LVT), ('\u{cb2c}', '\u{cb2c}', GC_LV), ('\u{cb2d}', '\u{cb47}', GC_LVT),
+ ('\u{cb48}', '\u{cb48}', GC_LV), ('\u{cb49}', '\u{cb63}', GC_LVT), ('\u{cb64}', '\u{cb64}',
+ GC_LV), ('\u{cb65}', '\u{cb7f}', GC_LVT), ('\u{cb80}', '\u{cb80}', GC_LV), ('\u{cb81}',
+ '\u{cb9b}', GC_LVT), ('\u{cb9c}', '\u{cb9c}', GC_LV), ('\u{cb9d}', '\u{cbb7}', GC_LVT),
+ ('\u{cbb8}', '\u{cbb8}', GC_LV), ('\u{cbb9}', '\u{cbd3}', GC_LVT), ('\u{cbd4}', '\u{cbd4}',
+ GC_LV), ('\u{cbd5}', '\u{cbef}', GC_LVT), ('\u{cbf0}', '\u{cbf0}', GC_LV), ('\u{cbf1}',
+ '\u{cc0b}', GC_LVT), ('\u{cc0c}', '\u{cc0c}', GC_LV), ('\u{cc0d}', '\u{cc27}', GC_LVT),
+ ('\u{cc28}', '\u{cc28}', GC_LV), ('\u{cc29}', '\u{cc43}', GC_LVT), ('\u{cc44}', '\u{cc44}',
+ GC_LV), ('\u{cc45}', '\u{cc5f}', GC_LVT), ('\u{cc60}', '\u{cc60}', GC_LV), ('\u{cc61}',
+ '\u{cc7b}', GC_LVT), ('\u{cc7c}', '\u{cc7c}', GC_LV), ('\u{cc7d}', '\u{cc97}', GC_LVT),
+ ('\u{cc98}', '\u{cc98}', GC_LV), ('\u{cc99}', '\u{ccb3}', GC_LVT), ('\u{ccb4}', '\u{ccb4}',
+ GC_LV), ('\u{ccb5}', '\u{cccf}', GC_LVT), ('\u{ccd0}', '\u{ccd0}', GC_LV), ('\u{ccd1}',
+ '\u{cceb}', GC_LVT), ('\u{ccec}', '\u{ccec}', GC_LV), ('\u{cced}', '\u{cd07}', GC_LVT),
+ ('\u{cd08}', '\u{cd08}', GC_LV), ('\u{cd09}', '\u{cd23}', GC_LVT), ('\u{cd24}', '\u{cd24}',
+ GC_LV), ('\u{cd25}', '\u{cd3f}', GC_LVT), ('\u{cd40}', '\u{cd40}', GC_LV), ('\u{cd41}',
+ '\u{cd5b}', GC_LVT), ('\u{cd5c}', '\u{cd5c}', GC_LV), ('\u{cd5d}', '\u{cd77}', GC_LVT),
+ ('\u{cd78}', '\u{cd78}', GC_LV), ('\u{cd79}', '\u{cd93}', GC_LVT), ('\u{cd94}', '\u{cd94}',
+ GC_LV), ('\u{cd95}', '\u{cdaf}', GC_LVT), ('\u{cdb0}', '\u{cdb0}', GC_LV), ('\u{cdb1}',
+ '\u{cdcb}', GC_LVT), ('\u{cdcc}', '\u{cdcc}', GC_LV), ('\u{cdcd}', '\u{cde7}', GC_LVT),
+ ('\u{cde8}', '\u{cde8}', GC_LV), ('\u{cde9}', '\u{ce03}', GC_LVT), ('\u{ce04}', '\u{ce04}',
+ GC_LV), ('\u{ce05}', '\u{ce1f}', GC_LVT), ('\u{ce20}', '\u{ce20}', GC_LV), ('\u{ce21}',
+ '\u{ce3b}', GC_LVT), ('\u{ce3c}', '\u{ce3c}', GC_LV), ('\u{ce3d}', '\u{ce57}', GC_LVT),
+ ('\u{ce58}', '\u{ce58}', GC_LV), ('\u{ce59}', '\u{ce73}', GC_LVT), ('\u{ce74}', '\u{ce74}',
+ GC_LV), ('\u{ce75}', '\u{ce8f}', GC_LVT), ('\u{ce90}', '\u{ce90}', GC_LV), ('\u{ce91}',
+ '\u{ceab}', GC_LVT), ('\u{ceac}', '\u{ceac}', GC_LV), ('\u{cead}', '\u{cec7}', GC_LVT),
+ ('\u{cec8}', '\u{cec8}', GC_LV), ('\u{cec9}', '\u{cee3}', GC_LVT), ('\u{cee4}', '\u{cee4}',
+ GC_LV), ('\u{cee5}', '\u{ceff}', GC_LVT), ('\u{cf00}', '\u{cf00}', GC_LV), ('\u{cf01}',
+ '\u{cf1b}', GC_LVT), ('\u{cf1c}', '\u{cf1c}', GC_LV), ('\u{cf1d}', '\u{cf37}', GC_LVT),
+ ('\u{cf38}', '\u{cf38}', GC_LV), ('\u{cf39}', '\u{cf53}', GC_LVT), ('\u{cf54}', '\u{cf54}',
+ GC_LV), ('\u{cf55}', '\u{cf6f}', GC_LVT), ('\u{cf70}', '\u{cf70}', GC_LV), ('\u{cf71}',
+ '\u{cf8b}', GC_LVT), ('\u{cf8c}', '\u{cf8c}', GC_LV), ('\u{cf8d}', '\u{cfa7}', GC_LVT),
+ ('\u{cfa8}', '\u{cfa8}', GC_LV), ('\u{cfa9}', '\u{cfc3}', GC_LVT), ('\u{cfc4}', '\u{cfc4}',
+ GC_LV), ('\u{cfc5}', '\u{cfdf}', GC_LVT), ('\u{cfe0}', '\u{cfe0}', GC_LV), ('\u{cfe1}',
+ '\u{cffb}', GC_LVT), ('\u{cffc}', '\u{cffc}', GC_LV), ('\u{cffd}', '\u{d017}', GC_LVT),
+ ('\u{d018}', '\u{d018}', GC_LV), ('\u{d019}', '\u{d033}', GC_LVT), ('\u{d034}', '\u{d034}',
+ GC_LV), ('\u{d035}', '\u{d04f}', GC_LVT), ('\u{d050}', '\u{d050}', GC_LV), ('\u{d051}',
+ '\u{d06b}', GC_LVT), ('\u{d06c}', '\u{d06c}', GC_LV), ('\u{d06d}', '\u{d087}', GC_LVT),
+ ('\u{d088}', '\u{d088}', GC_LV), ('\u{d089}', '\u{d0a3}', GC_LVT), ('\u{d0a4}', '\u{d0a4}',
+ GC_LV), ('\u{d0a5}', '\u{d0bf}', GC_LVT), ('\u{d0c0}', '\u{d0c0}', GC_LV), ('\u{d0c1}',
+ '\u{d0db}', GC_LVT), ('\u{d0dc}', '\u{d0dc}', GC_LV), ('\u{d0dd}', '\u{d0f7}', GC_LVT),
+ ('\u{d0f8}', '\u{d0f8}', GC_LV), ('\u{d0f9}', '\u{d113}', GC_LVT), ('\u{d114}', '\u{d114}',
+ GC_LV), ('\u{d115}', '\u{d12f}', GC_LVT), ('\u{d130}', '\u{d130}', GC_LV), ('\u{d131}',
+ '\u{d14b}', GC_LVT), ('\u{d14c}', '\u{d14c}', GC_LV), ('\u{d14d}', '\u{d167}', GC_LVT),
+ ('\u{d168}', '\u{d168}', GC_LV), ('\u{d169}', '\u{d183}', GC_LVT), ('\u{d184}', '\u{d184}',
+ GC_LV), ('\u{d185}', '\u{d19f}', GC_LVT), ('\u{d1a0}', '\u{d1a0}', GC_LV), ('\u{d1a1}',
+ '\u{d1bb}', GC_LVT), ('\u{d1bc}', '\u{d1bc}', GC_LV), ('\u{d1bd}', '\u{d1d7}', GC_LVT),
+ ('\u{d1d8}', '\u{d1d8}', GC_LV), ('\u{d1d9}', '\u{d1f3}', GC_LVT), ('\u{d1f4}', '\u{d1f4}',
+ GC_LV), ('\u{d1f5}', '\u{d20f}', GC_LVT), ('\u{d210}', '\u{d210}', GC_LV), ('\u{d211}',
+ '\u{d22b}', GC_LVT), ('\u{d22c}', '\u{d22c}', GC_LV), ('\u{d22d}', '\u{d247}', GC_LVT),
+ ('\u{d248}', '\u{d248}', GC_LV), ('\u{d249}', '\u{d263}', GC_LVT), ('\u{d264}', '\u{d264}',
+ GC_LV), ('\u{d265}', '\u{d27f}', GC_LVT), ('\u{d280}', '\u{d280}', GC_LV), ('\u{d281}',
+ '\u{d29b}', GC_LVT), ('\u{d29c}', '\u{d29c}', GC_LV), ('\u{d29d}', '\u{d2b7}', GC_LVT),
+ ('\u{d2b8}', '\u{d2b8}', GC_LV), ('\u{d2b9}', '\u{d2d3}', GC_LVT), ('\u{d2d4}', '\u{d2d4}',
+ GC_LV), ('\u{d2d5}', '\u{d2ef}', GC_LVT), ('\u{d2f0}', '\u{d2f0}', GC_LV), ('\u{d2f1}',
+ '\u{d30b}', GC_LVT), ('\u{d30c}', '\u{d30c}', GC_LV), ('\u{d30d}', '\u{d327}', GC_LVT),
+ ('\u{d328}', '\u{d328}', GC_LV), ('\u{d329}', '\u{d343}', GC_LVT), ('\u{d344}', '\u{d344}',
+ GC_LV), ('\u{d345}', '\u{d35f}', GC_LVT), ('\u{d360}', '\u{d360}', GC_LV), ('\u{d361}',
+ '\u{d37b}', GC_LVT), ('\u{d37c}', '\u{d37c}', GC_LV), ('\u{d37d}', '\u{d397}', GC_LVT),
+ ('\u{d398}', '\u{d398}', GC_LV), ('\u{d399}', '\u{d3b3}', GC_LVT), ('\u{d3b4}', '\u{d3b4}',
+ GC_LV), ('\u{d3b5}', '\u{d3cf}', GC_LVT), ('\u{d3d0}', '\u{d3d0}', GC_LV), ('\u{d3d1}',
+ '\u{d3eb}', GC_LVT), ('\u{d3ec}', '\u{d3ec}', GC_LV), ('\u{d3ed}', '\u{d407}', GC_LVT),
+ ('\u{d408}', '\u{d408}', GC_LV), ('\u{d409}', '\u{d423}', GC_LVT), ('\u{d424}', '\u{d424}',
+ GC_LV), ('\u{d425}', '\u{d43f}', GC_LVT), ('\u{d440}', '\u{d440}', GC_LV), ('\u{d441}',
+ '\u{d45b}', GC_LVT), ('\u{d45c}', '\u{d45c}', GC_LV), ('\u{d45d}', '\u{d477}', GC_LVT),
+ ('\u{d478}', '\u{d478}', GC_LV), ('\u{d479}', '\u{d493}', GC_LVT), ('\u{d494}', '\u{d494}',
+ GC_LV), ('\u{d495}', '\u{d4af}', GC_LVT), ('\u{d4b0}', '\u{d4b0}', GC_LV), ('\u{d4b1}',
+ '\u{d4cb}', GC_LVT), ('\u{d4cc}', '\u{d4cc}', GC_LV), ('\u{d4cd}', '\u{d4e7}', GC_LVT),
+ ('\u{d4e8}', '\u{d4e8}', GC_LV), ('\u{d4e9}', '\u{d503}', GC_LVT), ('\u{d504}', '\u{d504}',
+ GC_LV), ('\u{d505}', '\u{d51f}', GC_LVT), ('\u{d520}', '\u{d520}', GC_LV), ('\u{d521}',
+ '\u{d53b}', GC_LVT), ('\u{d53c}', '\u{d53c}', GC_LV), ('\u{d53d}', '\u{d557}', GC_LVT),
+ ('\u{d558}', '\u{d558}', GC_LV), ('\u{d559}', '\u{d573}', GC_LVT), ('\u{d574}', '\u{d574}',
+ GC_LV), ('\u{d575}', '\u{d58f}', GC_LVT), ('\u{d590}', '\u{d590}', GC_LV), ('\u{d591}',
+ '\u{d5ab}', GC_LVT), ('\u{d5ac}', '\u{d5ac}', GC_LV), ('\u{d5ad}', '\u{d5c7}', GC_LVT),
+ ('\u{d5c8}', '\u{d5c8}', GC_LV), ('\u{d5c9}', '\u{d5e3}', GC_LVT), ('\u{d5e4}', '\u{d5e4}',
+ GC_LV), ('\u{d5e5}', '\u{d5ff}', GC_LVT), ('\u{d600}', '\u{d600}', GC_LV), ('\u{d601}',
+ '\u{d61b}', GC_LVT), ('\u{d61c}', '\u{d61c}', GC_LV), ('\u{d61d}', '\u{d637}', GC_LVT),
+ ('\u{d638}', '\u{d638}', GC_LV), ('\u{d639}', '\u{d653}', GC_LVT), ('\u{d654}', '\u{d654}',
+ GC_LV), ('\u{d655}', '\u{d66f}', GC_LVT), ('\u{d670}', '\u{d670}', GC_LV), ('\u{d671}',
+ '\u{d68b}', GC_LVT), ('\u{d68c}', '\u{d68c}', GC_LV), ('\u{d68d}', '\u{d6a7}', GC_LVT),
+ ('\u{d6a8}', '\u{d6a8}', GC_LV), ('\u{d6a9}', '\u{d6c3}', GC_LVT), ('\u{d6c4}', '\u{d6c4}',
+ GC_LV), ('\u{d6c5}', '\u{d6df}', GC_LVT), ('\u{d6e0}', '\u{d6e0}', GC_LV), ('\u{d6e1}',
+ '\u{d6fb}', GC_LVT), ('\u{d6fc}', '\u{d6fc}', GC_LV), ('\u{d6fd}', '\u{d717}', GC_LVT),
+ ('\u{d718}', '\u{d718}', GC_LV), ('\u{d719}', '\u{d733}', GC_LVT), ('\u{d734}', '\u{d734}',
+ GC_LV), ('\u{d735}', '\u{d74f}', GC_LVT), ('\u{d750}', '\u{d750}', GC_LV), ('\u{d751}',
+ '\u{d76b}', GC_LVT), ('\u{d76c}', '\u{d76c}', GC_LV), ('\u{d76d}', '\u{d787}', GC_LVT),
+ ('\u{d788}', '\u{d788}', GC_LV), ('\u{d789}', '\u{d7a3}', GC_LVT), ('\u{d7b0}', '\u{d7c6}',
+ GC_V), ('\u{d7cb}', '\u{d7fb}', GC_T), ('\u{fb1e}', '\u{fb1e}', GC_Extend), ('\u{fe00}',
+ '\u{fe0f}', GC_Extend), ('\u{fe20}', '\u{fe2f}', GC_Extend), ('\u{feff}', '\u{feff}',
+ GC_Control), ('\u{ff9e}', '\u{ff9f}', GC_Extend), ('\u{fff0}', '\u{fffb}', GC_Control),
+ ('\u{101fd}', '\u{101fd}', GC_Extend), ('\u{102e0}', '\u{102e0}', GC_Extend), ('\u{10376}',
+ '\u{1037a}', GC_Extend), ('\u{10a01}', '\u{10a03}', GC_Extend), ('\u{10a05}', '\u{10a06}',
+ GC_Extend), ('\u{10a0c}', '\u{10a0f}', GC_Extend), ('\u{10a38}', '\u{10a3a}', GC_Extend),
+ ('\u{10a3f}', '\u{10a3f}', GC_Extend), ('\u{10ae5}', '\u{10ae6}', GC_Extend), ('\u{10d24}',
+ '\u{10d27}', GC_Extend), ('\u{10f46}', '\u{10f50}', GC_Extend), ('\u{11000}', '\u{11000}',
+ GC_SpacingMark), ('\u{11001}', '\u{11001}', GC_Extend), ('\u{11002}', '\u{11002}',
+ GC_SpacingMark), ('\u{11038}', '\u{11046}', GC_Extend), ('\u{1107f}', '\u{11081}',
+ GC_Extend), ('\u{11082}', '\u{11082}', GC_SpacingMark), ('\u{110b0}', '\u{110b2}',
+ GC_SpacingMark), ('\u{110b3}', '\u{110b6}', GC_Extend), ('\u{110b7}', '\u{110b8}',
+ GC_SpacingMark), ('\u{110b9}', '\u{110ba}', GC_Extend), ('\u{110bd}', '\u{110bd}',
+ GC_Prepend), ('\u{110cd}', '\u{110cd}', GC_Prepend), ('\u{11100}', '\u{11102}', GC_Extend),
+ ('\u{11127}', '\u{1112b}', GC_Extend), ('\u{1112c}', '\u{1112c}', GC_SpacingMark),
+ ('\u{1112d}', '\u{11134}', GC_Extend), ('\u{11145}', '\u{11146}', GC_SpacingMark),
+ ('\u{11173}', '\u{11173}', GC_Extend), ('\u{11180}', '\u{11181}', GC_Extend), ('\u{11182}',
+ '\u{11182}', GC_SpacingMark), ('\u{111b3}', '\u{111b5}', GC_SpacingMark), ('\u{111b6}',
+ '\u{111be}', GC_Extend), ('\u{111bf}', '\u{111c0}', GC_SpacingMark), ('\u{111c2}',
+ '\u{111c3}', GC_Prepend), ('\u{111c9}', '\u{111cc}', GC_Extend), ('\u{1122c}', '\u{1122e}',
+ GC_SpacingMark), ('\u{1122f}', '\u{11231}', GC_Extend), ('\u{11232}', '\u{11233}',
+ GC_SpacingMark), ('\u{11234}', '\u{11234}', GC_Extend), ('\u{11235}', '\u{11235}',
+ GC_SpacingMark), ('\u{11236}', '\u{11237}', GC_Extend), ('\u{1123e}', '\u{1123e}',
+ GC_Extend), ('\u{112df}', '\u{112df}', GC_Extend), ('\u{112e0}', '\u{112e2}',
+ GC_SpacingMark), ('\u{112e3}', '\u{112ea}', GC_Extend), ('\u{11300}', '\u{11301}',
+ GC_Extend), ('\u{11302}', '\u{11303}', GC_SpacingMark), ('\u{1133b}', '\u{1133c}',
+ GC_Extend), ('\u{1133e}', '\u{1133e}', GC_Extend), ('\u{1133f}', '\u{1133f}',
+ GC_SpacingMark), ('\u{11340}', '\u{11340}', GC_Extend), ('\u{11341}', '\u{11344}',
+ GC_SpacingMark), ('\u{11347}', '\u{11348}', GC_SpacingMark), ('\u{1134b}', '\u{1134d}',
+ GC_SpacingMark), ('\u{11357}', '\u{11357}', GC_Extend), ('\u{11362}', '\u{11363}',
+ GC_SpacingMark), ('\u{11366}', '\u{1136c}', GC_Extend), ('\u{11370}', '\u{11374}',
+ GC_Extend), ('\u{11435}', '\u{11437}', GC_SpacingMark), ('\u{11438}', '\u{1143f}',
+ GC_Extend), ('\u{11440}', '\u{11441}', GC_SpacingMark), ('\u{11442}', '\u{11444}',
+ GC_Extend), ('\u{11445}', '\u{11445}', GC_SpacingMark), ('\u{11446}', '\u{11446}',
+ GC_Extend), ('\u{1145e}', '\u{1145e}', GC_Extend), ('\u{114b0}', '\u{114b0}', GC_Extend),
+ ('\u{114b1}', '\u{114b2}', GC_SpacingMark), ('\u{114b3}', '\u{114b8}', GC_Extend),
+ ('\u{114b9}', '\u{114b9}', GC_SpacingMark), ('\u{114ba}', '\u{114ba}', GC_Extend),
+ ('\u{114bb}', '\u{114bc}', GC_SpacingMark), ('\u{114bd}', '\u{114bd}', GC_Extend),
+ ('\u{114be}', '\u{114be}', GC_SpacingMark), ('\u{114bf}', '\u{114c0}', GC_Extend),
+ ('\u{114c1}', '\u{114c1}', GC_SpacingMark), ('\u{114c2}', '\u{114c3}', GC_Extend),
+ ('\u{115af}', '\u{115af}', GC_Extend), ('\u{115b0}', '\u{115b1}', GC_SpacingMark),
+ ('\u{115b2}', '\u{115b5}', GC_Extend), ('\u{115b8}', '\u{115bb}', GC_SpacingMark),
+ ('\u{115bc}', '\u{115bd}', GC_Extend), ('\u{115be}', '\u{115be}', GC_SpacingMark),
+ ('\u{115bf}', '\u{115c0}', GC_Extend), ('\u{115dc}', '\u{115dd}', GC_Extend), ('\u{11630}',
+ '\u{11632}', GC_SpacingMark), ('\u{11633}', '\u{1163a}', GC_Extend), ('\u{1163b}',
+ '\u{1163c}', GC_SpacingMark), ('\u{1163d}', '\u{1163d}', GC_Extend), ('\u{1163e}',
+ '\u{1163e}', GC_SpacingMark), ('\u{1163f}', '\u{11640}', GC_Extend), ('\u{116ab}',
+ '\u{116ab}', GC_Extend), ('\u{116ac}', '\u{116ac}', GC_SpacingMark), ('\u{116ad}',
+ '\u{116ad}', GC_Extend), ('\u{116ae}', '\u{116af}', GC_SpacingMark), ('\u{116b0}',
+ '\u{116b5}', GC_Extend), ('\u{116b6}', '\u{116b6}', GC_SpacingMark), ('\u{116b7}',
+ '\u{116b7}', GC_Extend), ('\u{1171d}', '\u{1171f}', GC_Extend), ('\u{11720}', '\u{11721}',
+ GC_SpacingMark), ('\u{11722}', '\u{11725}', GC_Extend), ('\u{11726}', '\u{11726}',
+ GC_SpacingMark), ('\u{11727}', '\u{1172b}', GC_Extend), ('\u{1182c}', '\u{1182e}',
+ GC_SpacingMark), ('\u{1182f}', '\u{11837}', GC_Extend), ('\u{11838}', '\u{11838}',
+ GC_SpacingMark), ('\u{11839}', '\u{1183a}', GC_Extend), ('\u{119d1}', '\u{119d3}',
+ GC_SpacingMark), ('\u{119d4}', '\u{119d7}', GC_Extend), ('\u{119da}', '\u{119db}',
+ GC_Extend), ('\u{119dc}', '\u{119df}', GC_SpacingMark), ('\u{119e0}', '\u{119e0}',
+ GC_Extend), ('\u{119e4}', '\u{119e4}', GC_SpacingMark), ('\u{11a01}', '\u{11a0a}',
+ GC_Extend), ('\u{11a33}', '\u{11a38}', GC_Extend), ('\u{11a39}', '\u{11a39}',
+ GC_SpacingMark), ('\u{11a3a}', '\u{11a3a}', GC_Prepend), ('\u{11a3b}', '\u{11a3e}',
+ GC_Extend), ('\u{11a47}', '\u{11a47}', GC_Extend), ('\u{11a51}', '\u{11a56}', GC_Extend),
+ ('\u{11a57}', '\u{11a58}', GC_SpacingMark), ('\u{11a59}', '\u{11a5b}', GC_Extend),
+ ('\u{11a84}', '\u{11a89}', GC_Prepend), ('\u{11a8a}', '\u{11a96}', GC_Extend), ('\u{11a97}',
+ '\u{11a97}', GC_SpacingMark), ('\u{11a98}', '\u{11a99}', GC_Extend), ('\u{11c2f}',
+ '\u{11c2f}', GC_SpacingMark), ('\u{11c30}', '\u{11c36}', GC_Extend), ('\u{11c38}',
+ '\u{11c3d}', GC_Extend), ('\u{11c3e}', '\u{11c3e}', GC_SpacingMark), ('\u{11c3f}',
+ '\u{11c3f}', GC_Extend), ('\u{11c92}', '\u{11ca7}', GC_Extend), ('\u{11ca9}', '\u{11ca9}',
+ GC_SpacingMark), ('\u{11caa}', '\u{11cb0}', GC_Extend), ('\u{11cb1}', '\u{11cb1}',
+ GC_SpacingMark), ('\u{11cb2}', '\u{11cb3}', GC_Extend), ('\u{11cb4}', '\u{11cb4}',
+ GC_SpacingMark), ('\u{11cb5}', '\u{11cb6}', GC_Extend), ('\u{11d31}', '\u{11d36}',
+ GC_Extend), ('\u{11d3a}', '\u{11d3a}', GC_Extend), ('\u{11d3c}', '\u{11d3d}', GC_Extend),
+ ('\u{11d3f}', '\u{11d45}', GC_Extend), ('\u{11d46}', '\u{11d46}', GC_Prepend), ('\u{11d47}',
+ '\u{11d47}', GC_Extend), ('\u{11d8a}', '\u{11d8e}', GC_SpacingMark), ('\u{11d90}',
+ '\u{11d91}', GC_Extend), ('\u{11d93}', '\u{11d94}', GC_SpacingMark), ('\u{11d95}',
+ '\u{11d95}', GC_Extend), ('\u{11d96}', '\u{11d96}', GC_SpacingMark), ('\u{11d97}',
+ '\u{11d97}', GC_Extend), ('\u{11ef3}', '\u{11ef4}', GC_Extend), ('\u{11ef5}', '\u{11ef6}',
+ GC_SpacingMark), ('\u{13430}', '\u{13438}', GC_Control), ('\u{16af0}', '\u{16af4}',
+ GC_Extend), ('\u{16b30}', '\u{16b36}', GC_Extend), ('\u{16f4f}', '\u{16f4f}', GC_Extend),
+ ('\u{16f51}', '\u{16f87}', GC_SpacingMark), ('\u{16f8f}', '\u{16f92}', GC_Extend),
+ ('\u{1bc9d}', '\u{1bc9e}', GC_Extend), ('\u{1bca0}', '\u{1bca3}', GC_Control), ('\u{1d165}',
+ '\u{1d165}', GC_Extend), ('\u{1d166}', '\u{1d166}', GC_SpacingMark), ('\u{1d167}',
+ '\u{1d169}', GC_Extend), ('\u{1d16d}', '\u{1d16d}', GC_SpacingMark), ('\u{1d16e}',
+ '\u{1d172}', GC_Extend), ('\u{1d173}', '\u{1d17a}', GC_Control), ('\u{1d17b}', '\u{1d182}',
+ GC_Extend), ('\u{1d185}', '\u{1d18b}', GC_Extend), ('\u{1d1aa}', '\u{1d1ad}', GC_Extend),
+ ('\u{1d242}', '\u{1d244}', GC_Extend), ('\u{1da00}', '\u{1da36}', GC_Extend), ('\u{1da3b}',
+ '\u{1da6c}', GC_Extend), ('\u{1da75}', '\u{1da75}', GC_Extend), ('\u{1da84}', '\u{1da84}',
+ GC_Extend), ('\u{1da9b}', '\u{1da9f}', GC_Extend), ('\u{1daa1}', '\u{1daaf}', GC_Extend),
+ ('\u{1e000}', '\u{1e006}', GC_Extend), ('\u{1e008}', '\u{1e018}', GC_Extend), ('\u{1e01b}',
+ '\u{1e021}', GC_Extend), ('\u{1e023}', '\u{1e024}', GC_Extend), ('\u{1e026}', '\u{1e02a}',
+ GC_Extend), ('\u{1e130}', '\u{1e136}', GC_Extend), ('\u{1e2ec}', '\u{1e2ef}', GC_Extend),
+ ('\u{1e8d0}', '\u{1e8d6}', GC_Extend), ('\u{1e944}', '\u{1e94a}', GC_Extend), ('\u{1f000}',
+ '\u{1f0ff}', GC_Extended_Pictographic), ('\u{1f10d}', '\u{1f10f}',
+ GC_Extended_Pictographic), ('\u{1f12f}', '\u{1f12f}', GC_Extended_Pictographic),
+ ('\u{1f16c}', '\u{1f171}', GC_Extended_Pictographic), ('\u{1f17e}', '\u{1f17f}',
+ GC_Extended_Pictographic), ('\u{1f18e}', '\u{1f18e}', GC_Extended_Pictographic),
+ ('\u{1f191}', '\u{1f19a}', GC_Extended_Pictographic), ('\u{1f1ad}', '\u{1f1e5}',
+ GC_Extended_Pictographic), ('\u{1f1e6}', '\u{1f1ff}', GC_Regional_Indicator), ('\u{1f201}',
+ '\u{1f20f}', GC_Extended_Pictographic), ('\u{1f21a}', '\u{1f21a}',
+ GC_Extended_Pictographic), ('\u{1f22f}', '\u{1f22f}', GC_Extended_Pictographic),
+ ('\u{1f232}', '\u{1f23a}', GC_Extended_Pictographic), ('\u{1f23c}', '\u{1f23f}',
+ GC_Extended_Pictographic), ('\u{1f249}', '\u{1f3fa}', GC_Extended_Pictographic),
+ ('\u{1f3fb}', '\u{1f3ff}', GC_Extend), ('\u{1f400}', '\u{1f53d}', GC_Extended_Pictographic),
+ ('\u{1f546}', '\u{1f64f}', GC_Extended_Pictographic), ('\u{1f680}', '\u{1f6ff}',
+ GC_Extended_Pictographic), ('\u{1f774}', '\u{1f77f}', GC_Extended_Pictographic),
+ ('\u{1f7d5}', '\u{1f7ff}', GC_Extended_Pictographic), ('\u{1f80c}', '\u{1f80f}',
+ GC_Extended_Pictographic), ('\u{1f848}', '\u{1f84f}', GC_Extended_Pictographic),
+ ('\u{1f85a}', '\u{1f85f}', GC_Extended_Pictographic), ('\u{1f888}', '\u{1f88f}',
+ GC_Extended_Pictographic), ('\u{1f8ae}', '\u{1f8ff}', GC_Extended_Pictographic),
+ ('\u{1f90c}', '\u{1f93a}', GC_Extended_Pictographic), ('\u{1f93c}', '\u{1f945}',
+ GC_Extended_Pictographic), ('\u{1f947}', '\u{1fffd}', GC_Extended_Pictographic),
+ ('\u{e0000}', '\u{e001f}', GC_Control), ('\u{e0020}', '\u{e007f}', GC_Extend), ('\u{e0080}',
+ '\u{e00ff}', GC_Control), ('\u{e0100}', '\u{e01ef}', GC_Extend), ('\u{e01f0}', '\u{e0fff}',
+ GC_Control)
+ ];
+
+}
+
+pub mod word {
+ use core::result::Result::{Ok, Err};
+
+ pub use self::WordCat::*;
+
+ #[allow(non_camel_case_types)]
+ #[derive(Clone, Copy, PartialEq, Eq, Debug)]
+ pub enum WordCat {
+ WC_ALetter,
+ WC_Any,
+ WC_CR,
+ WC_Double_Quote,
+ WC_Extend,
+ WC_ExtendNumLet,
+ WC_Format,
+ WC_Hebrew_Letter,
+ WC_Katakana,
+ WC_LF,
+ WC_MidLetter,
+ WC_MidNum,
+ WC_MidNumLet,
+ WC_Newline,
+ WC_Numeric,
+ WC_Regional_Indicator,
+ WC_Single_Quote,
+ WC_WSegSpace,
+ WC_ZWJ,
+ }
+
+ fn bsearch_range_value_table(c: char, r: &'static [(char, char, WordCat)]) -> WordCat {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ match r.binary_search_by(|&(lo, hi, _)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }) {
+ Ok(idx) => {
+ let (_, _, cat) = r[idx];
+ cat
+ }
+ Err(_) => WC_Any
+ }
+ }
+
+ pub fn word_category(c: char) -> WordCat {
+ bsearch_range_value_table(c, word_cat_table)
+ }
+
+ const word_cat_table: &'static [(char, char, WordCat)] = &[
+ ('\u{a}', '\u{a}', WC_LF), ('\u{b}', '\u{c}', WC_Newline), ('\u{d}', '\u{d}', WC_CR),
+ ('\u{20}', '\u{20}', WC_WSegSpace), ('\u{22}', '\u{22}', WC_Double_Quote), ('\u{27}',
+ '\u{27}', WC_Single_Quote), ('\u{2c}', '\u{2c}', WC_MidNum), ('\u{2e}', '\u{2e}',
+ WC_MidNumLet), ('\u{30}', '\u{39}', WC_Numeric), ('\u{3a}', '\u{3a}', WC_MidLetter),
+ ('\u{3b}', '\u{3b}', WC_MidNum), ('\u{41}', '\u{5a}', WC_ALetter), ('\u{5f}', '\u{5f}',
+ WC_ExtendNumLet), ('\u{61}', '\u{7a}', WC_ALetter), ('\u{85}', '\u{85}', WC_Newline),
+ ('\u{aa}', '\u{aa}', WC_ALetter), ('\u{ad}', '\u{ad}', WC_Format), ('\u{b5}', '\u{b5}',
+ WC_ALetter), ('\u{b7}', '\u{b7}', WC_MidLetter), ('\u{ba}', '\u{ba}', WC_ALetter),
+ ('\u{c0}', '\u{d6}', WC_ALetter), ('\u{d8}', '\u{f6}', WC_ALetter), ('\u{f8}', '\u{2d7}',
+ WC_ALetter), ('\u{2de}', '\u{2e4}', WC_ALetter), ('\u{2ec}', '\u{2ff}', WC_ALetter),
+ ('\u{300}', '\u{36f}', WC_Extend), ('\u{370}', '\u{374}', WC_ALetter), ('\u{376}',
+ '\u{377}', WC_ALetter), ('\u{37a}', '\u{37d}', WC_ALetter), ('\u{37e}', '\u{37e}',
+ WC_MidNum), ('\u{37f}', '\u{37f}', WC_ALetter), ('\u{386}', '\u{386}', WC_ALetter),
+ ('\u{387}', '\u{387}', WC_MidLetter), ('\u{388}', '\u{38a}', WC_ALetter), ('\u{38c}',
+ '\u{38c}', WC_ALetter), ('\u{38e}', '\u{3a1}', WC_ALetter), ('\u{3a3}', '\u{3f5}',
+ WC_ALetter), ('\u{3f7}', '\u{481}', WC_ALetter), ('\u{483}', '\u{489}', WC_Extend),
+ ('\u{48a}', '\u{52f}', WC_ALetter), ('\u{531}', '\u{556}', WC_ALetter), ('\u{559}',
+ '\u{559}', WC_ALetter), ('\u{55b}', '\u{55c}', WC_ALetter), ('\u{55e}', '\u{55e}',
+ WC_ALetter), ('\u{560}', '\u{588}', WC_ALetter), ('\u{589}', '\u{589}', WC_MidNum),
+ ('\u{591}', '\u{5bd}', WC_Extend), ('\u{5bf}', '\u{5bf}', WC_Extend), ('\u{5c1}', '\u{5c2}',
+ WC_Extend), ('\u{5c4}', '\u{5c5}', WC_Extend), ('\u{5c7}', '\u{5c7}', WC_Extend),
+ ('\u{5d0}', '\u{5ea}', WC_Hebrew_Letter), ('\u{5ef}', '\u{5f2}', WC_Hebrew_Letter),
+ ('\u{5f3}', '\u{5f3}', WC_ALetter), ('\u{5f4}', '\u{5f4}', WC_MidLetter), ('\u{600}',
+ '\u{605}', WC_Format), ('\u{60c}', '\u{60d}', WC_MidNum), ('\u{610}', '\u{61a}', WC_Extend),
+ ('\u{61c}', '\u{61c}', WC_Format), ('\u{620}', '\u{64a}', WC_ALetter), ('\u{64b}',
+ '\u{65f}', WC_Extend), ('\u{660}', '\u{669}', WC_Numeric), ('\u{66b}', '\u{66b}',
+ WC_Numeric), ('\u{66c}', '\u{66c}', WC_MidNum), ('\u{66e}', '\u{66f}', WC_ALetter),
+ ('\u{670}', '\u{670}', WC_Extend), ('\u{671}', '\u{6d3}', WC_ALetter), ('\u{6d5}',
+ '\u{6d5}', WC_ALetter), ('\u{6d6}', '\u{6dc}', WC_Extend), ('\u{6dd}', '\u{6dd}',
+ WC_Format), ('\u{6df}', '\u{6e4}', WC_Extend), ('\u{6e5}', '\u{6e6}', WC_ALetter),
+ ('\u{6e7}', '\u{6e8}', WC_Extend), ('\u{6ea}', '\u{6ed}', WC_Extend), ('\u{6ee}', '\u{6ef}',
+ WC_ALetter), ('\u{6f0}', '\u{6f9}', WC_Numeric), ('\u{6fa}', '\u{6fc}', WC_ALetter),
+ ('\u{6ff}', '\u{6ff}', WC_ALetter), ('\u{70f}', '\u{70f}', WC_Format), ('\u{710}',
+ '\u{710}', WC_ALetter), ('\u{711}', '\u{711}', WC_Extend), ('\u{712}', '\u{72f}',
+ WC_ALetter), ('\u{730}', '\u{74a}', WC_Extend), ('\u{74d}', '\u{7a5}', WC_ALetter),
+ ('\u{7a6}', '\u{7b0}', WC_Extend), ('\u{7b1}', '\u{7b1}', WC_ALetter), ('\u{7c0}',
+ '\u{7c9}', WC_Numeric), ('\u{7ca}', '\u{7ea}', WC_ALetter), ('\u{7eb}', '\u{7f3}',
+ WC_Extend), ('\u{7f4}', '\u{7f5}', WC_ALetter), ('\u{7f8}', '\u{7f8}', WC_MidNum),
+ ('\u{7fa}', '\u{7fa}', WC_ALetter), ('\u{7fd}', '\u{7fd}', WC_Extend), ('\u{800}',
+ '\u{815}', WC_ALetter), ('\u{816}', '\u{819}', WC_Extend), ('\u{81a}', '\u{81a}',
+ WC_ALetter), ('\u{81b}', '\u{823}', WC_Extend), ('\u{824}', '\u{824}', WC_ALetter),
+ ('\u{825}', '\u{827}', WC_Extend), ('\u{828}', '\u{828}', WC_ALetter), ('\u{829}',
+ '\u{82d}', WC_Extend), ('\u{840}', '\u{858}', WC_ALetter), ('\u{859}', '\u{85b}',
+ WC_Extend), ('\u{860}', '\u{86a}', WC_ALetter), ('\u{8a0}', '\u{8b4}', WC_ALetter),
+ ('\u{8b6}', '\u{8bd}', WC_ALetter), ('\u{8d3}', '\u{8e1}', WC_Extend), ('\u{8e2}',
+ '\u{8e2}', WC_Format), ('\u{8e3}', '\u{903}', WC_Extend), ('\u{904}', '\u{939}',
+ WC_ALetter), ('\u{93a}', '\u{93c}', WC_Extend), ('\u{93d}', '\u{93d}', WC_ALetter),
+ ('\u{93e}', '\u{94f}', WC_Extend), ('\u{950}', '\u{950}', WC_ALetter), ('\u{951}',
+ '\u{957}', WC_Extend), ('\u{958}', '\u{961}', WC_ALetter), ('\u{962}', '\u{963}',
+ WC_Extend), ('\u{966}', '\u{96f}', WC_Numeric), ('\u{971}', '\u{980}', WC_ALetter),
+ ('\u{981}', '\u{983}', WC_Extend), ('\u{985}', '\u{98c}', WC_ALetter), ('\u{98f}',
+ '\u{990}', WC_ALetter), ('\u{993}', '\u{9a8}', WC_ALetter), ('\u{9aa}', '\u{9b0}',
+ WC_ALetter), ('\u{9b2}', '\u{9b2}', WC_ALetter), ('\u{9b6}', '\u{9b9}', WC_ALetter),
+ ('\u{9bc}', '\u{9bc}', WC_Extend), ('\u{9bd}', '\u{9bd}', WC_ALetter), ('\u{9be}',
+ '\u{9c4}', WC_Extend), ('\u{9c7}', '\u{9c8}', WC_Extend), ('\u{9cb}', '\u{9cd}', WC_Extend),
+ ('\u{9ce}', '\u{9ce}', WC_ALetter), ('\u{9d7}', '\u{9d7}', WC_Extend), ('\u{9dc}',
+ '\u{9dd}', WC_ALetter), ('\u{9df}', '\u{9e1}', WC_ALetter), ('\u{9e2}', '\u{9e3}',
+ WC_Extend), ('\u{9e6}', '\u{9ef}', WC_Numeric), ('\u{9f0}', '\u{9f1}', WC_ALetter),
+ ('\u{9fc}', '\u{9fc}', WC_ALetter), ('\u{9fe}', '\u{9fe}', WC_Extend), ('\u{a01}',
+ '\u{a03}', WC_Extend), ('\u{a05}', '\u{a0a}', WC_ALetter), ('\u{a0f}', '\u{a10}',
+ WC_ALetter), ('\u{a13}', '\u{a28}', WC_ALetter), ('\u{a2a}', '\u{a30}', WC_ALetter),
+ ('\u{a32}', '\u{a33}', WC_ALetter), ('\u{a35}', '\u{a36}', WC_ALetter), ('\u{a38}',
+ '\u{a39}', WC_ALetter), ('\u{a3c}', '\u{a3c}', WC_Extend), ('\u{a3e}', '\u{a42}',
+ WC_Extend), ('\u{a47}', '\u{a48}', WC_Extend), ('\u{a4b}', '\u{a4d}', WC_Extend),
+ ('\u{a51}', '\u{a51}', WC_Extend), ('\u{a59}', '\u{a5c}', WC_ALetter), ('\u{a5e}',
+ '\u{a5e}', WC_ALetter), ('\u{a66}', '\u{a6f}', WC_Numeric), ('\u{a70}', '\u{a71}',
+ WC_Extend), ('\u{a72}', '\u{a74}', WC_ALetter), ('\u{a75}', '\u{a75}', WC_Extend),
+ ('\u{a81}', '\u{a83}', WC_Extend), ('\u{a85}', '\u{a8d}', WC_ALetter), ('\u{a8f}',
+ '\u{a91}', WC_ALetter), ('\u{a93}', '\u{aa8}', WC_ALetter), ('\u{aaa}', '\u{ab0}',
+ WC_ALetter), ('\u{ab2}', '\u{ab3}', WC_ALetter), ('\u{ab5}', '\u{ab9}', WC_ALetter),
+ ('\u{abc}', '\u{abc}', WC_Extend), ('\u{abd}', '\u{abd}', WC_ALetter), ('\u{abe}',
+ '\u{ac5}', WC_Extend), ('\u{ac7}', '\u{ac9}', WC_Extend), ('\u{acb}', '\u{acd}', WC_Extend),
+ ('\u{ad0}', '\u{ad0}', WC_ALetter), ('\u{ae0}', '\u{ae1}', WC_ALetter), ('\u{ae2}',
+ '\u{ae3}', WC_Extend), ('\u{ae6}', '\u{aef}', WC_Numeric), ('\u{af9}', '\u{af9}',
+ WC_ALetter), ('\u{afa}', '\u{aff}', WC_Extend), ('\u{b01}', '\u{b03}', WC_Extend),
+ ('\u{b05}', '\u{b0c}', WC_ALetter), ('\u{b0f}', '\u{b10}', WC_ALetter), ('\u{b13}',
+ '\u{b28}', WC_ALetter), ('\u{b2a}', '\u{b30}', WC_ALetter), ('\u{b32}', '\u{b33}',
+ WC_ALetter), ('\u{b35}', '\u{b39}', WC_ALetter), ('\u{b3c}', '\u{b3c}', WC_Extend),
+ ('\u{b3d}', '\u{b3d}', WC_ALetter), ('\u{b3e}', '\u{b44}', WC_Extend), ('\u{b47}',
+ '\u{b48}', WC_Extend), ('\u{b4b}', '\u{b4d}', WC_Extend), ('\u{b56}', '\u{b57}', WC_Extend),
+ ('\u{b5c}', '\u{b5d}', WC_ALetter), ('\u{b5f}', '\u{b61}', WC_ALetter), ('\u{b62}',
+ '\u{b63}', WC_Extend), ('\u{b66}', '\u{b6f}', WC_Numeric), ('\u{b71}', '\u{b71}',
+ WC_ALetter), ('\u{b82}', '\u{b82}', WC_Extend), ('\u{b83}', '\u{b83}', WC_ALetter),
+ ('\u{b85}', '\u{b8a}', WC_ALetter), ('\u{b8e}', '\u{b90}', WC_ALetter), ('\u{b92}',
+ '\u{b95}', WC_ALetter), ('\u{b99}', '\u{b9a}', WC_ALetter), ('\u{b9c}', '\u{b9c}',
+ WC_ALetter), ('\u{b9e}', '\u{b9f}', WC_ALetter), ('\u{ba3}', '\u{ba4}', WC_ALetter),
+ ('\u{ba8}', '\u{baa}', WC_ALetter), ('\u{bae}', '\u{bb9}', WC_ALetter), ('\u{bbe}',
+ '\u{bc2}', WC_Extend), ('\u{bc6}', '\u{bc8}', WC_Extend), ('\u{bca}', '\u{bcd}', WC_Extend),
+ ('\u{bd0}', '\u{bd0}', WC_ALetter), ('\u{bd7}', '\u{bd7}', WC_Extend), ('\u{be6}',
+ '\u{bef}', WC_Numeric), ('\u{c00}', '\u{c04}', WC_Extend), ('\u{c05}', '\u{c0c}',
+ WC_ALetter), ('\u{c0e}', '\u{c10}', WC_ALetter), ('\u{c12}', '\u{c28}', WC_ALetter),
+ ('\u{c2a}', '\u{c39}', WC_ALetter), ('\u{c3d}', '\u{c3d}', WC_ALetter), ('\u{c3e}',
+ '\u{c44}', WC_Extend), ('\u{c46}', '\u{c48}', WC_Extend), ('\u{c4a}', '\u{c4d}', WC_Extend),
+ ('\u{c55}', '\u{c56}', WC_Extend), ('\u{c58}', '\u{c5a}', WC_ALetter), ('\u{c60}',
+ '\u{c61}', WC_ALetter), ('\u{c62}', '\u{c63}', WC_Extend), ('\u{c66}', '\u{c6f}',
+ WC_Numeric), ('\u{c80}', '\u{c80}', WC_ALetter), ('\u{c81}', '\u{c83}', WC_Extend),
+ ('\u{c85}', '\u{c8c}', WC_ALetter), ('\u{c8e}', '\u{c90}', WC_ALetter), ('\u{c92}',
+ '\u{ca8}', WC_ALetter), ('\u{caa}', '\u{cb3}', WC_ALetter), ('\u{cb5}', '\u{cb9}',
+ WC_ALetter), ('\u{cbc}', '\u{cbc}', WC_Extend), ('\u{cbd}', '\u{cbd}', WC_ALetter),
+ ('\u{cbe}', '\u{cc4}', WC_Extend), ('\u{cc6}', '\u{cc8}', WC_Extend), ('\u{cca}', '\u{ccd}',
+ WC_Extend), ('\u{cd5}', '\u{cd6}', WC_Extend), ('\u{cde}', '\u{cde}', WC_ALetter),
+ ('\u{ce0}', '\u{ce1}', WC_ALetter), ('\u{ce2}', '\u{ce3}', WC_Extend), ('\u{ce6}',
+ '\u{cef}', WC_Numeric), ('\u{cf1}', '\u{cf2}', WC_ALetter), ('\u{d00}', '\u{d03}',
+ WC_Extend), ('\u{d05}', '\u{d0c}', WC_ALetter), ('\u{d0e}', '\u{d10}', WC_ALetter),
+ ('\u{d12}', '\u{d3a}', WC_ALetter), ('\u{d3b}', '\u{d3c}', WC_Extend), ('\u{d3d}',
+ '\u{d3d}', WC_ALetter), ('\u{d3e}', '\u{d44}', WC_Extend), ('\u{d46}', '\u{d48}',
+ WC_Extend), ('\u{d4a}', '\u{d4d}', WC_Extend), ('\u{d4e}', '\u{d4e}', WC_ALetter),
+ ('\u{d54}', '\u{d56}', WC_ALetter), ('\u{d57}', '\u{d57}', WC_Extend), ('\u{d5f}',
+ '\u{d61}', WC_ALetter), ('\u{d62}', '\u{d63}', WC_Extend), ('\u{d66}', '\u{d6f}',
+ WC_Numeric), ('\u{d7a}', '\u{d7f}', WC_ALetter), ('\u{d82}', '\u{d83}', WC_Extend),
+ ('\u{d85}', '\u{d96}', WC_ALetter), ('\u{d9a}', '\u{db1}', WC_ALetter), ('\u{db3}',
+ '\u{dbb}', WC_ALetter), ('\u{dbd}', '\u{dbd}', WC_ALetter), ('\u{dc0}', '\u{dc6}',
+ WC_ALetter), ('\u{dca}', '\u{dca}', WC_Extend), ('\u{dcf}', '\u{dd4}', WC_Extend),
+ ('\u{dd6}', '\u{dd6}', WC_Extend), ('\u{dd8}', '\u{ddf}', WC_Extend), ('\u{de6}', '\u{def}',
+ WC_Numeric), ('\u{df2}', '\u{df3}', WC_Extend), ('\u{e31}', '\u{e31}', WC_Extend),
+ ('\u{e34}', '\u{e3a}', WC_Extend), ('\u{e47}', '\u{e4e}', WC_Extend), ('\u{e50}', '\u{e59}',
+ WC_Numeric), ('\u{eb1}', '\u{eb1}', WC_Extend), ('\u{eb4}', '\u{ebc}', WC_Extend),
+ ('\u{ec8}', '\u{ecd}', WC_Extend), ('\u{ed0}', '\u{ed9}', WC_Numeric), ('\u{f00}',
+ '\u{f00}', WC_ALetter), ('\u{f18}', '\u{f19}', WC_Extend), ('\u{f20}', '\u{f29}',
+ WC_Numeric), ('\u{f35}', '\u{f35}', WC_Extend), ('\u{f37}', '\u{f37}', WC_Extend),
+ ('\u{f39}', '\u{f39}', WC_Extend), ('\u{f3e}', '\u{f3f}', WC_Extend), ('\u{f40}', '\u{f47}',
+ WC_ALetter), ('\u{f49}', '\u{f6c}', WC_ALetter), ('\u{f71}', '\u{f84}', WC_Extend),
+ ('\u{f86}', '\u{f87}', WC_Extend), ('\u{f88}', '\u{f8c}', WC_ALetter), ('\u{f8d}',
+ '\u{f97}', WC_Extend), ('\u{f99}', '\u{fbc}', WC_Extend), ('\u{fc6}', '\u{fc6}', WC_Extend),
+ ('\u{102b}', '\u{103e}', WC_Extend), ('\u{1040}', '\u{1049}', WC_Numeric), ('\u{1056}',
+ '\u{1059}', WC_Extend), ('\u{105e}', '\u{1060}', WC_Extend), ('\u{1062}', '\u{1064}',
+ WC_Extend), ('\u{1067}', '\u{106d}', WC_Extend), ('\u{1071}', '\u{1074}', WC_Extend),
+ ('\u{1082}', '\u{108d}', WC_Extend), ('\u{108f}', '\u{108f}', WC_Extend), ('\u{1090}',
+ '\u{1099}', WC_Numeric), ('\u{109a}', '\u{109d}', WC_Extend), ('\u{10a0}', '\u{10c5}',
+ WC_ALetter), ('\u{10c7}', '\u{10c7}', WC_ALetter), ('\u{10cd}', '\u{10cd}', WC_ALetter),
+ ('\u{10d0}', '\u{10fa}', WC_ALetter), ('\u{10fc}', '\u{1248}', WC_ALetter), ('\u{124a}',
+ '\u{124d}', WC_ALetter), ('\u{1250}', '\u{1256}', WC_ALetter), ('\u{1258}', '\u{1258}',
+ WC_ALetter), ('\u{125a}', '\u{125d}', WC_ALetter), ('\u{1260}', '\u{1288}', WC_ALetter),
+ ('\u{128a}', '\u{128d}', WC_ALetter), ('\u{1290}', '\u{12b0}', WC_ALetter), ('\u{12b2}',
+ '\u{12b5}', WC_ALetter), ('\u{12b8}', '\u{12be}', WC_ALetter), ('\u{12c0}', '\u{12c0}',
+ WC_ALetter), ('\u{12c2}', '\u{12c5}', WC_ALetter), ('\u{12c8}', '\u{12d6}', WC_ALetter),
+ ('\u{12d8}', '\u{1310}', WC_ALetter), ('\u{1312}', '\u{1315}', WC_ALetter), ('\u{1318}',
+ '\u{135a}', WC_ALetter), ('\u{135d}', '\u{135f}', WC_Extend), ('\u{1380}', '\u{138f}',
+ WC_ALetter), ('\u{13a0}', '\u{13f5}', WC_ALetter), ('\u{13f8}', '\u{13fd}', WC_ALetter),
+ ('\u{1401}', '\u{166c}', WC_ALetter), ('\u{166f}', '\u{167f}', WC_ALetter), ('\u{1680}',
+ '\u{1680}', WC_WSegSpace), ('\u{1681}', '\u{169a}', WC_ALetter), ('\u{16a0}', '\u{16ea}',
+ WC_ALetter), ('\u{16ee}', '\u{16f8}', WC_ALetter), ('\u{1700}', '\u{170c}', WC_ALetter),
+ ('\u{170e}', '\u{1711}', WC_ALetter), ('\u{1712}', '\u{1714}', WC_Extend), ('\u{1720}',
+ '\u{1731}', WC_ALetter), ('\u{1732}', '\u{1734}', WC_Extend), ('\u{1740}', '\u{1751}',
+ WC_ALetter), ('\u{1752}', '\u{1753}', WC_Extend), ('\u{1760}', '\u{176c}', WC_ALetter),
+ ('\u{176e}', '\u{1770}', WC_ALetter), ('\u{1772}', '\u{1773}', WC_Extend), ('\u{17b4}',
+ '\u{17d3}', WC_Extend), ('\u{17dd}', '\u{17dd}', WC_Extend), ('\u{17e0}', '\u{17e9}',
+ WC_Numeric), ('\u{180b}', '\u{180d}', WC_Extend), ('\u{180e}', '\u{180e}', WC_Format),
+ ('\u{1810}', '\u{1819}', WC_Numeric), ('\u{1820}', '\u{1878}', WC_ALetter), ('\u{1880}',
+ '\u{1884}', WC_ALetter), ('\u{1885}', '\u{1886}', WC_Extend), ('\u{1887}', '\u{18a8}',
+ WC_ALetter), ('\u{18a9}', '\u{18a9}', WC_Extend), ('\u{18aa}', '\u{18aa}', WC_ALetter),
+ ('\u{18b0}', '\u{18f5}', WC_ALetter), ('\u{1900}', '\u{191e}', WC_ALetter), ('\u{1920}',
+ '\u{192b}', WC_Extend), ('\u{1930}', '\u{193b}', WC_Extend), ('\u{1946}', '\u{194f}',
+ WC_Numeric), ('\u{19d0}', '\u{19d9}', WC_Numeric), ('\u{1a00}', '\u{1a16}', WC_ALetter),
+ ('\u{1a17}', '\u{1a1b}', WC_Extend), ('\u{1a55}', '\u{1a5e}', WC_Extend), ('\u{1a60}',
+ '\u{1a7c}', WC_Extend), ('\u{1a7f}', '\u{1a7f}', WC_Extend), ('\u{1a80}', '\u{1a89}',
+ WC_Numeric), ('\u{1a90}', '\u{1a99}', WC_Numeric), ('\u{1ab0}', '\u{1abe}', WC_Extend),
+ ('\u{1b00}', '\u{1b04}', WC_Extend), ('\u{1b05}', '\u{1b33}', WC_ALetter), ('\u{1b34}',
+ '\u{1b44}', WC_Extend), ('\u{1b45}', '\u{1b4b}', WC_ALetter), ('\u{1b50}', '\u{1b59}',
+ WC_Numeric), ('\u{1b6b}', '\u{1b73}', WC_Extend), ('\u{1b80}', '\u{1b82}', WC_Extend),
+ ('\u{1b83}', '\u{1ba0}', WC_ALetter), ('\u{1ba1}', '\u{1bad}', WC_Extend), ('\u{1bae}',
+ '\u{1baf}', WC_ALetter), ('\u{1bb0}', '\u{1bb9}', WC_Numeric), ('\u{1bba}', '\u{1be5}',
+ WC_ALetter), ('\u{1be6}', '\u{1bf3}', WC_Extend), ('\u{1c00}', '\u{1c23}', WC_ALetter),
+ ('\u{1c24}', '\u{1c37}', WC_Extend), ('\u{1c40}', '\u{1c49}', WC_Numeric), ('\u{1c4d}',
+ '\u{1c4f}', WC_ALetter), ('\u{1c50}', '\u{1c59}', WC_Numeric), ('\u{1c5a}', '\u{1c7d}',
+ WC_ALetter), ('\u{1c80}', '\u{1c88}', WC_ALetter), ('\u{1c90}', '\u{1cba}', WC_ALetter),
+ ('\u{1cbd}', '\u{1cbf}', WC_ALetter), ('\u{1cd0}', '\u{1cd2}', WC_Extend), ('\u{1cd4}',
+ '\u{1ce8}', WC_Extend), ('\u{1ce9}', '\u{1cec}', WC_ALetter), ('\u{1ced}', '\u{1ced}',
+ WC_Extend), ('\u{1cee}', '\u{1cf3}', WC_ALetter), ('\u{1cf4}', '\u{1cf4}', WC_Extend),
+ ('\u{1cf5}', '\u{1cf6}', WC_ALetter), ('\u{1cf7}', '\u{1cf9}', WC_Extend), ('\u{1cfa}',
+ '\u{1cfa}', WC_ALetter), ('\u{1d00}', '\u{1dbf}', WC_ALetter), ('\u{1dc0}', '\u{1df9}',
+ WC_Extend), ('\u{1dfb}', '\u{1dff}', WC_Extend), ('\u{1e00}', '\u{1f15}', WC_ALetter),
+ ('\u{1f18}', '\u{1f1d}', WC_ALetter), ('\u{1f20}', '\u{1f45}', WC_ALetter), ('\u{1f48}',
+ '\u{1f4d}', WC_ALetter), ('\u{1f50}', '\u{1f57}', WC_ALetter), ('\u{1f59}', '\u{1f59}',
+ WC_ALetter), ('\u{1f5b}', '\u{1f5b}', WC_ALetter), ('\u{1f5d}', '\u{1f5d}', WC_ALetter),
+ ('\u{1f5f}', '\u{1f7d}', WC_ALetter), ('\u{1f80}', '\u{1fb4}', WC_ALetter), ('\u{1fb6}',
+ '\u{1fbc}', WC_ALetter), ('\u{1fbe}', '\u{1fbe}', WC_ALetter), ('\u{1fc2}', '\u{1fc4}',
+ WC_ALetter), ('\u{1fc6}', '\u{1fcc}', WC_ALetter), ('\u{1fd0}', '\u{1fd3}', WC_ALetter),
+ ('\u{1fd6}', '\u{1fdb}', WC_ALetter), ('\u{1fe0}', '\u{1fec}', WC_ALetter), ('\u{1ff2}',
+ '\u{1ff4}', WC_ALetter), ('\u{1ff6}', '\u{1ffc}', WC_ALetter), ('\u{2000}', '\u{2006}',
+ WC_WSegSpace), ('\u{2008}', '\u{200a}', WC_WSegSpace), ('\u{200c}', '\u{200c}', WC_Extend),
+ ('\u{200d}', '\u{200d}', WC_ZWJ), ('\u{200e}', '\u{200f}', WC_Format), ('\u{2018}',
+ '\u{2019}', WC_MidNumLet), ('\u{2024}', '\u{2024}', WC_MidNumLet), ('\u{2027}', '\u{2027}',
+ WC_MidLetter), ('\u{2028}', '\u{2029}', WC_Newline), ('\u{202a}', '\u{202e}', WC_Format),
+ ('\u{202f}', '\u{202f}', WC_ExtendNumLet), ('\u{203f}', '\u{2040}', WC_ExtendNumLet),
+ ('\u{2044}', '\u{2044}', WC_MidNum), ('\u{2054}', '\u{2054}', WC_ExtendNumLet), ('\u{205f}',
+ '\u{205f}', WC_WSegSpace), ('\u{2060}', '\u{2064}', WC_Format), ('\u{2066}', '\u{206f}',
+ WC_Format), ('\u{2071}', '\u{2071}', WC_ALetter), ('\u{207f}', '\u{207f}', WC_ALetter),
+ ('\u{2090}', '\u{209c}', WC_ALetter), ('\u{20d0}', '\u{20f0}', WC_Extend), ('\u{2102}',
+ '\u{2102}', WC_ALetter), ('\u{2107}', '\u{2107}', WC_ALetter), ('\u{210a}', '\u{2113}',
+ WC_ALetter), ('\u{2115}', '\u{2115}', WC_ALetter), ('\u{2119}', '\u{211d}', WC_ALetter),
+ ('\u{2124}', '\u{2124}', WC_ALetter), ('\u{2126}', '\u{2126}', WC_ALetter), ('\u{2128}',
+ '\u{2128}', WC_ALetter), ('\u{212a}', '\u{212d}', WC_ALetter), ('\u{212f}', '\u{2139}',
+ WC_ALetter), ('\u{213c}', '\u{213f}', WC_ALetter), ('\u{2145}', '\u{2149}', WC_ALetter),
+ ('\u{214e}', '\u{214e}', WC_ALetter), ('\u{2160}', '\u{2188}', WC_ALetter), ('\u{24b6}',
+ '\u{24e9}', WC_ALetter), ('\u{2c00}', '\u{2c2e}', WC_ALetter), ('\u{2c30}', '\u{2c5e}',
+ WC_ALetter), ('\u{2c60}', '\u{2ce4}', WC_ALetter), ('\u{2ceb}', '\u{2cee}', WC_ALetter),
+ ('\u{2cef}', '\u{2cf1}', WC_Extend), ('\u{2cf2}', '\u{2cf3}', WC_ALetter), ('\u{2d00}',
+ '\u{2d25}', WC_ALetter), ('\u{2d27}', '\u{2d27}', WC_ALetter), ('\u{2d2d}', '\u{2d2d}',
+ WC_ALetter), ('\u{2d30}', '\u{2d67}', WC_ALetter), ('\u{2d6f}', '\u{2d6f}', WC_ALetter),
+ ('\u{2d7f}', '\u{2d7f}', WC_Extend), ('\u{2d80}', '\u{2d96}', WC_ALetter), ('\u{2da0}',
+ '\u{2da6}', WC_ALetter), ('\u{2da8}', '\u{2dae}', WC_ALetter), ('\u{2db0}', '\u{2db6}',
+ WC_ALetter), ('\u{2db8}', '\u{2dbe}', WC_ALetter), ('\u{2dc0}', '\u{2dc6}', WC_ALetter),
+ ('\u{2dc8}', '\u{2dce}', WC_ALetter), ('\u{2dd0}', '\u{2dd6}', WC_ALetter), ('\u{2dd8}',
+ '\u{2dde}', WC_ALetter), ('\u{2de0}', '\u{2dff}', WC_Extend), ('\u{2e2f}', '\u{2e2f}',
+ WC_ALetter), ('\u{3000}', '\u{3000}', WC_WSegSpace), ('\u{3005}', '\u{3005}', WC_ALetter),
+ ('\u{302a}', '\u{302f}', WC_Extend), ('\u{3031}', '\u{3035}', WC_Katakana), ('\u{303b}',
+ '\u{303c}', WC_ALetter), ('\u{3099}', '\u{309a}', WC_Extend), ('\u{309b}', '\u{309c}',
+ WC_Katakana), ('\u{30a0}', '\u{30fa}', WC_Katakana), ('\u{30fc}', '\u{30ff}', WC_Katakana),
+ ('\u{3105}', '\u{312f}', WC_ALetter), ('\u{3131}', '\u{318e}', WC_ALetter), ('\u{31a0}',
+ '\u{31ba}', WC_ALetter), ('\u{31f0}', '\u{31ff}', WC_Katakana), ('\u{32d0}', '\u{32fe}',
+ WC_Katakana), ('\u{3300}', '\u{3357}', WC_Katakana), ('\u{a000}', '\u{a48c}', WC_ALetter),
+ ('\u{a4d0}', '\u{a4fd}', WC_ALetter), ('\u{a500}', '\u{a60c}', WC_ALetter), ('\u{a610}',
+ '\u{a61f}', WC_ALetter), ('\u{a620}', '\u{a629}', WC_Numeric), ('\u{a62a}', '\u{a62b}',
+ WC_ALetter), ('\u{a640}', '\u{a66e}', WC_ALetter), ('\u{a66f}', '\u{a672}', WC_Extend),
+ ('\u{a674}', '\u{a67d}', WC_Extend), ('\u{a67f}', '\u{a69d}', WC_ALetter), ('\u{a69e}',
+ '\u{a69f}', WC_Extend), ('\u{a6a0}', '\u{a6ef}', WC_ALetter), ('\u{a6f0}', '\u{a6f1}',
+ WC_Extend), ('\u{a717}', '\u{a7bf}', WC_ALetter), ('\u{a7c2}', '\u{a7c6}', WC_ALetter),
+ ('\u{a7f7}', '\u{a801}', WC_ALetter), ('\u{a802}', '\u{a802}', WC_Extend), ('\u{a803}',
+ '\u{a805}', WC_ALetter), ('\u{a806}', '\u{a806}', WC_Extend), ('\u{a807}', '\u{a80a}',
+ WC_ALetter), ('\u{a80b}', '\u{a80b}', WC_Extend), ('\u{a80c}', '\u{a822}', WC_ALetter),
+ ('\u{a823}', '\u{a827}', WC_Extend), ('\u{a840}', '\u{a873}', WC_ALetter), ('\u{a880}',
+ '\u{a881}', WC_Extend), ('\u{a882}', '\u{a8b3}', WC_ALetter), ('\u{a8b4}', '\u{a8c5}',
+ WC_Extend), ('\u{a8d0}', '\u{a8d9}', WC_Numeric), ('\u{a8e0}', '\u{a8f1}', WC_Extend),
+ ('\u{a8f2}', '\u{a8f7}', WC_ALetter), ('\u{a8fb}', '\u{a8fb}', WC_ALetter), ('\u{a8fd}',
+ '\u{a8fe}', WC_ALetter), ('\u{a8ff}', '\u{a8ff}', WC_Extend), ('\u{a900}', '\u{a909}',
+ WC_Numeric), ('\u{a90a}', '\u{a925}', WC_ALetter), ('\u{a926}', '\u{a92d}', WC_Extend),
+ ('\u{a930}', '\u{a946}', WC_ALetter), ('\u{a947}', '\u{a953}', WC_Extend), ('\u{a960}',
+ '\u{a97c}', WC_ALetter), ('\u{a980}', '\u{a983}', WC_Extend), ('\u{a984}', '\u{a9b2}',
+ WC_ALetter), ('\u{a9b3}', '\u{a9c0}', WC_Extend), ('\u{a9cf}', '\u{a9cf}', WC_ALetter),
+ ('\u{a9d0}', '\u{a9d9}', WC_Numeric), ('\u{a9e5}', '\u{a9e5}', WC_Extend), ('\u{a9f0}',
+ '\u{a9f9}', WC_Numeric), ('\u{aa00}', '\u{aa28}', WC_ALetter), ('\u{aa29}', '\u{aa36}',
+ WC_Extend), ('\u{aa40}', '\u{aa42}', WC_ALetter), ('\u{aa43}', '\u{aa43}', WC_Extend),
+ ('\u{aa44}', '\u{aa4b}', WC_ALetter), ('\u{aa4c}', '\u{aa4d}', WC_Extend), ('\u{aa50}',
+ '\u{aa59}', WC_Numeric), ('\u{aa7b}', '\u{aa7d}', WC_Extend), ('\u{aab0}', '\u{aab0}',
+ WC_Extend), ('\u{aab2}', '\u{aab4}', WC_Extend), ('\u{aab7}', '\u{aab8}', WC_Extend),
+ ('\u{aabe}', '\u{aabf}', WC_Extend), ('\u{aac1}', '\u{aac1}', WC_Extend), ('\u{aae0}',
+ '\u{aaea}', WC_ALetter), ('\u{aaeb}', '\u{aaef}', WC_Extend), ('\u{aaf2}', '\u{aaf4}',
+ WC_ALetter), ('\u{aaf5}', '\u{aaf6}', WC_Extend), ('\u{ab01}', '\u{ab06}', WC_ALetter),
+ ('\u{ab09}', '\u{ab0e}', WC_ALetter), ('\u{ab11}', '\u{ab16}', WC_ALetter), ('\u{ab20}',
+ '\u{ab26}', WC_ALetter), ('\u{ab28}', '\u{ab2e}', WC_ALetter), ('\u{ab30}', '\u{ab67}',
+ WC_ALetter), ('\u{ab70}', '\u{abe2}', WC_ALetter), ('\u{abe3}', '\u{abea}', WC_Extend),
+ ('\u{abec}', '\u{abed}', WC_Extend), ('\u{abf0}', '\u{abf9}', WC_Numeric), ('\u{ac00}',
+ '\u{d7a3}', WC_ALetter), ('\u{d7b0}', '\u{d7c6}', WC_ALetter), ('\u{d7cb}', '\u{d7fb}',
+ WC_ALetter), ('\u{fb00}', '\u{fb06}', WC_ALetter), ('\u{fb13}', '\u{fb17}', WC_ALetter),
+ ('\u{fb1d}', '\u{fb1d}', WC_Hebrew_Letter), ('\u{fb1e}', '\u{fb1e}', WC_Extend),
+ ('\u{fb1f}', '\u{fb28}', WC_Hebrew_Letter), ('\u{fb2a}', '\u{fb36}', WC_Hebrew_Letter),
+ ('\u{fb38}', '\u{fb3c}', WC_Hebrew_Letter), ('\u{fb3e}', '\u{fb3e}', WC_Hebrew_Letter),
+ ('\u{fb40}', '\u{fb41}', WC_Hebrew_Letter), ('\u{fb43}', '\u{fb44}', WC_Hebrew_Letter),
+ ('\u{fb46}', '\u{fb4f}', WC_Hebrew_Letter), ('\u{fb50}', '\u{fbb1}', WC_ALetter),
+ ('\u{fbd3}', '\u{fd3d}', WC_ALetter), ('\u{fd50}', '\u{fd8f}', WC_ALetter), ('\u{fd92}',
+ '\u{fdc7}', WC_ALetter), ('\u{fdf0}', '\u{fdfb}', WC_ALetter), ('\u{fe00}', '\u{fe0f}',
+ WC_Extend), ('\u{fe10}', '\u{fe10}', WC_MidNum), ('\u{fe13}', '\u{fe13}', WC_MidLetter),
+ ('\u{fe14}', '\u{fe14}', WC_MidNum), ('\u{fe20}', '\u{fe2f}', WC_Extend), ('\u{fe33}',
+ '\u{fe34}', WC_ExtendNumLet), ('\u{fe4d}', '\u{fe4f}', WC_ExtendNumLet), ('\u{fe50}',
+ '\u{fe50}', WC_MidNum), ('\u{fe52}', '\u{fe52}', WC_MidNumLet), ('\u{fe54}', '\u{fe54}',
+ WC_MidNum), ('\u{fe55}', '\u{fe55}', WC_MidLetter), ('\u{fe70}', '\u{fe74}', WC_ALetter),
+ ('\u{fe76}', '\u{fefc}', WC_ALetter), ('\u{feff}', '\u{feff}', WC_Format), ('\u{ff07}',
+ '\u{ff07}', WC_MidNumLet), ('\u{ff0c}', '\u{ff0c}', WC_MidNum), ('\u{ff0e}', '\u{ff0e}',
+ WC_MidNumLet), ('\u{ff10}', '\u{ff19}', WC_Numeric), ('\u{ff1a}', '\u{ff1a}', WC_MidLetter),
+ ('\u{ff1b}', '\u{ff1b}', WC_MidNum), ('\u{ff21}', '\u{ff3a}', WC_ALetter), ('\u{ff3f}',
+ '\u{ff3f}', WC_ExtendNumLet), ('\u{ff41}', '\u{ff5a}', WC_ALetter), ('\u{ff66}', '\u{ff9d}',
+ WC_Katakana), ('\u{ff9e}', '\u{ff9f}', WC_Extend), ('\u{ffa0}', '\u{ffbe}', WC_ALetter),
+ ('\u{ffc2}', '\u{ffc7}', WC_ALetter), ('\u{ffca}', '\u{ffcf}', WC_ALetter), ('\u{ffd2}',
+ '\u{ffd7}', WC_ALetter), ('\u{ffda}', '\u{ffdc}', WC_ALetter), ('\u{fff9}', '\u{fffb}',
+ WC_Format), ('\u{10000}', '\u{1000b}', WC_ALetter), ('\u{1000d}', '\u{10026}', WC_ALetter),
+ ('\u{10028}', '\u{1003a}', WC_ALetter), ('\u{1003c}', '\u{1003d}', WC_ALetter),
+ ('\u{1003f}', '\u{1004d}', WC_ALetter), ('\u{10050}', '\u{1005d}', WC_ALetter),
+ ('\u{10080}', '\u{100fa}', WC_ALetter), ('\u{10140}', '\u{10174}', WC_ALetter),
+ ('\u{101fd}', '\u{101fd}', WC_Extend), ('\u{10280}', '\u{1029c}', WC_ALetter), ('\u{102a0}',
+ '\u{102d0}', WC_ALetter), ('\u{102e0}', '\u{102e0}', WC_Extend), ('\u{10300}', '\u{1031f}',
+ WC_ALetter), ('\u{1032d}', '\u{1034a}', WC_ALetter), ('\u{10350}', '\u{10375}', WC_ALetter),
+ ('\u{10376}', '\u{1037a}', WC_Extend), ('\u{10380}', '\u{1039d}', WC_ALetter), ('\u{103a0}',
+ '\u{103c3}', WC_ALetter), ('\u{103c8}', '\u{103cf}', WC_ALetter), ('\u{103d1}', '\u{103d5}',
+ WC_ALetter), ('\u{10400}', '\u{1049d}', WC_ALetter), ('\u{104a0}', '\u{104a9}', WC_Numeric),
+ ('\u{104b0}', '\u{104d3}', WC_ALetter), ('\u{104d8}', '\u{104fb}', WC_ALetter),
+ ('\u{10500}', '\u{10527}', WC_ALetter), ('\u{10530}', '\u{10563}', WC_ALetter),
+ ('\u{10600}', '\u{10736}', WC_ALetter), ('\u{10740}', '\u{10755}', WC_ALetter),
+ ('\u{10760}', '\u{10767}', WC_ALetter), ('\u{10800}', '\u{10805}', WC_ALetter),
+ ('\u{10808}', '\u{10808}', WC_ALetter), ('\u{1080a}', '\u{10835}', WC_ALetter),
+ ('\u{10837}', '\u{10838}', WC_ALetter), ('\u{1083c}', '\u{1083c}', WC_ALetter),
+ ('\u{1083f}', '\u{10855}', WC_ALetter), ('\u{10860}', '\u{10876}', WC_ALetter),
+ ('\u{10880}', '\u{1089e}', WC_ALetter), ('\u{108e0}', '\u{108f2}', WC_ALetter),
+ ('\u{108f4}', '\u{108f5}', WC_ALetter), ('\u{10900}', '\u{10915}', WC_ALetter),
+ ('\u{10920}', '\u{10939}', WC_ALetter), ('\u{10980}', '\u{109b7}', WC_ALetter),
+ ('\u{109be}', '\u{109bf}', WC_ALetter), ('\u{10a00}', '\u{10a00}', WC_ALetter),
+ ('\u{10a01}', '\u{10a03}', WC_Extend), ('\u{10a05}', '\u{10a06}', WC_Extend), ('\u{10a0c}',
+ '\u{10a0f}', WC_Extend), ('\u{10a10}', '\u{10a13}', WC_ALetter), ('\u{10a15}', '\u{10a17}',
+ WC_ALetter), ('\u{10a19}', '\u{10a35}', WC_ALetter), ('\u{10a38}', '\u{10a3a}', WC_Extend),
+ ('\u{10a3f}', '\u{10a3f}', WC_Extend), ('\u{10a60}', '\u{10a7c}', WC_ALetter), ('\u{10a80}',
+ '\u{10a9c}', WC_ALetter), ('\u{10ac0}', '\u{10ac7}', WC_ALetter), ('\u{10ac9}', '\u{10ae4}',
+ WC_ALetter), ('\u{10ae5}', '\u{10ae6}', WC_Extend), ('\u{10b00}', '\u{10b35}', WC_ALetter),
+ ('\u{10b40}', '\u{10b55}', WC_ALetter), ('\u{10b60}', '\u{10b72}', WC_ALetter),
+ ('\u{10b80}', '\u{10b91}', WC_ALetter), ('\u{10c00}', '\u{10c48}', WC_ALetter),
+ ('\u{10c80}', '\u{10cb2}', WC_ALetter), ('\u{10cc0}', '\u{10cf2}', WC_ALetter),
+ ('\u{10d00}', '\u{10d23}', WC_ALetter), ('\u{10d24}', '\u{10d27}', WC_Extend), ('\u{10d30}',
+ '\u{10d39}', WC_Numeric), ('\u{10f00}', '\u{10f1c}', WC_ALetter), ('\u{10f27}', '\u{10f27}',
+ WC_ALetter), ('\u{10f30}', '\u{10f45}', WC_ALetter), ('\u{10f46}', '\u{10f50}', WC_Extend),
+ ('\u{10fe0}', '\u{10ff6}', WC_ALetter), ('\u{11000}', '\u{11002}', WC_Extend), ('\u{11003}',
+ '\u{11037}', WC_ALetter), ('\u{11038}', '\u{11046}', WC_Extend), ('\u{11066}', '\u{1106f}',
+ WC_Numeric), ('\u{1107f}', '\u{11082}', WC_Extend), ('\u{11083}', '\u{110af}', WC_ALetter),
+ ('\u{110b0}', '\u{110ba}', WC_Extend), ('\u{110bd}', '\u{110bd}', WC_Format), ('\u{110cd}',
+ '\u{110cd}', WC_Format), ('\u{110d0}', '\u{110e8}', WC_ALetter), ('\u{110f0}', '\u{110f9}',
+ WC_Numeric), ('\u{11100}', '\u{11102}', WC_Extend), ('\u{11103}', '\u{11126}', WC_ALetter),
+ ('\u{11127}', '\u{11134}', WC_Extend), ('\u{11136}', '\u{1113f}', WC_Numeric), ('\u{11144}',
+ '\u{11144}', WC_ALetter), ('\u{11145}', '\u{11146}', WC_Extend), ('\u{11150}', '\u{11172}',
+ WC_ALetter), ('\u{11173}', '\u{11173}', WC_Extend), ('\u{11176}', '\u{11176}', WC_ALetter),
+ ('\u{11180}', '\u{11182}', WC_Extend), ('\u{11183}', '\u{111b2}', WC_ALetter), ('\u{111b3}',
+ '\u{111c0}', WC_Extend), ('\u{111c1}', '\u{111c4}', WC_ALetter), ('\u{111c9}', '\u{111cc}',
+ WC_Extend), ('\u{111d0}', '\u{111d9}', WC_Numeric), ('\u{111da}', '\u{111da}', WC_ALetter),
+ ('\u{111dc}', '\u{111dc}', WC_ALetter), ('\u{11200}', '\u{11211}', WC_ALetter),
+ ('\u{11213}', '\u{1122b}', WC_ALetter), ('\u{1122c}', '\u{11237}', WC_Extend), ('\u{1123e}',
+ '\u{1123e}', WC_Extend), ('\u{11280}', '\u{11286}', WC_ALetter), ('\u{11288}', '\u{11288}',
+ WC_ALetter), ('\u{1128a}', '\u{1128d}', WC_ALetter), ('\u{1128f}', '\u{1129d}', WC_ALetter),
+ ('\u{1129f}', '\u{112a8}', WC_ALetter), ('\u{112b0}', '\u{112de}', WC_ALetter),
+ ('\u{112df}', '\u{112ea}', WC_Extend), ('\u{112f0}', '\u{112f9}', WC_Numeric), ('\u{11300}',
+ '\u{11303}', WC_Extend), ('\u{11305}', '\u{1130c}', WC_ALetter), ('\u{1130f}', '\u{11310}',
+ WC_ALetter), ('\u{11313}', '\u{11328}', WC_ALetter), ('\u{1132a}', '\u{11330}', WC_ALetter),
+ ('\u{11332}', '\u{11333}', WC_ALetter), ('\u{11335}', '\u{11339}', WC_ALetter),
+ ('\u{1133b}', '\u{1133c}', WC_Extend), ('\u{1133d}', '\u{1133d}', WC_ALetter), ('\u{1133e}',
+ '\u{11344}', WC_Extend), ('\u{11347}', '\u{11348}', WC_Extend), ('\u{1134b}', '\u{1134d}',
+ WC_Extend), ('\u{11350}', '\u{11350}', WC_ALetter), ('\u{11357}', '\u{11357}', WC_Extend),
+ ('\u{1135d}', '\u{11361}', WC_ALetter), ('\u{11362}', '\u{11363}', WC_Extend), ('\u{11366}',
+ '\u{1136c}', WC_Extend), ('\u{11370}', '\u{11374}', WC_Extend), ('\u{11400}', '\u{11434}',
+ WC_ALetter), ('\u{11435}', '\u{11446}', WC_Extend), ('\u{11447}', '\u{1144a}', WC_ALetter),
+ ('\u{11450}', '\u{11459}', WC_Numeric), ('\u{1145e}', '\u{1145e}', WC_Extend), ('\u{1145f}',
+ '\u{1145f}', WC_ALetter), ('\u{11480}', '\u{114af}', WC_ALetter), ('\u{114b0}', '\u{114c3}',
+ WC_Extend), ('\u{114c4}', '\u{114c5}', WC_ALetter), ('\u{114c7}', '\u{114c7}', WC_ALetter),
+ ('\u{114d0}', '\u{114d9}', WC_Numeric), ('\u{11580}', '\u{115ae}', WC_ALetter),
+ ('\u{115af}', '\u{115b5}', WC_Extend), ('\u{115b8}', '\u{115c0}', WC_Extend), ('\u{115d8}',
+ '\u{115db}', WC_ALetter), ('\u{115dc}', '\u{115dd}', WC_Extend), ('\u{11600}', '\u{1162f}',
+ WC_ALetter), ('\u{11630}', '\u{11640}', WC_Extend), ('\u{11644}', '\u{11644}', WC_ALetter),
+ ('\u{11650}', '\u{11659}', WC_Numeric), ('\u{11680}', '\u{116aa}', WC_ALetter),
+ ('\u{116ab}', '\u{116b7}', WC_Extend), ('\u{116b8}', '\u{116b8}', WC_ALetter), ('\u{116c0}',
+ '\u{116c9}', WC_Numeric), ('\u{1171d}', '\u{1172b}', WC_Extend), ('\u{11730}', '\u{11739}',
+ WC_Numeric), ('\u{11800}', '\u{1182b}', WC_ALetter), ('\u{1182c}', '\u{1183a}', WC_Extend),
+ ('\u{118a0}', '\u{118df}', WC_ALetter), ('\u{118e0}', '\u{118e9}', WC_Numeric),
+ ('\u{118ff}', '\u{118ff}', WC_ALetter), ('\u{119a0}', '\u{119a7}', WC_ALetter),
+ ('\u{119aa}', '\u{119d0}', WC_ALetter), ('\u{119d1}', '\u{119d7}', WC_Extend), ('\u{119da}',
+ '\u{119e0}', WC_Extend), ('\u{119e1}', '\u{119e1}', WC_ALetter), ('\u{119e3}', '\u{119e3}',
+ WC_ALetter), ('\u{119e4}', '\u{119e4}', WC_Extend), ('\u{11a00}', '\u{11a00}', WC_ALetter),
+ ('\u{11a01}', '\u{11a0a}', WC_Extend), ('\u{11a0b}', '\u{11a32}', WC_ALetter), ('\u{11a33}',
+ '\u{11a39}', WC_Extend), ('\u{11a3a}', '\u{11a3a}', WC_ALetter), ('\u{11a3b}', '\u{11a3e}',
+ WC_Extend), ('\u{11a47}', '\u{11a47}', WC_Extend), ('\u{11a50}', '\u{11a50}', WC_ALetter),
+ ('\u{11a51}', '\u{11a5b}', WC_Extend), ('\u{11a5c}', '\u{11a89}', WC_ALetter), ('\u{11a8a}',
+ '\u{11a99}', WC_Extend), ('\u{11a9d}', '\u{11a9d}', WC_ALetter), ('\u{11ac0}', '\u{11af8}',
+ WC_ALetter), ('\u{11c00}', '\u{11c08}', WC_ALetter), ('\u{11c0a}', '\u{11c2e}', WC_ALetter),
+ ('\u{11c2f}', '\u{11c36}', WC_Extend), ('\u{11c38}', '\u{11c3f}', WC_Extend), ('\u{11c40}',
+ '\u{11c40}', WC_ALetter), ('\u{11c50}', '\u{11c59}', WC_Numeric), ('\u{11c72}', '\u{11c8f}',
+ WC_ALetter), ('\u{11c92}', '\u{11ca7}', WC_Extend), ('\u{11ca9}', '\u{11cb6}', WC_Extend),
+ ('\u{11d00}', '\u{11d06}', WC_ALetter), ('\u{11d08}', '\u{11d09}', WC_ALetter),
+ ('\u{11d0b}', '\u{11d30}', WC_ALetter), ('\u{11d31}', '\u{11d36}', WC_Extend), ('\u{11d3a}',
+ '\u{11d3a}', WC_Extend), ('\u{11d3c}', '\u{11d3d}', WC_Extend), ('\u{11d3f}', '\u{11d45}',
+ WC_Extend), ('\u{11d46}', '\u{11d46}', WC_ALetter), ('\u{11d47}', '\u{11d47}', WC_Extend),
+ ('\u{11d50}', '\u{11d59}', WC_Numeric), ('\u{11d60}', '\u{11d65}', WC_ALetter),
+ ('\u{11d67}', '\u{11d68}', WC_ALetter), ('\u{11d6a}', '\u{11d89}', WC_ALetter),
+ ('\u{11d8a}', '\u{11d8e}', WC_Extend), ('\u{11d90}', '\u{11d91}', WC_Extend), ('\u{11d93}',
+ '\u{11d97}', WC_Extend), ('\u{11d98}', '\u{11d98}', WC_ALetter), ('\u{11da0}', '\u{11da9}',
+ WC_Numeric), ('\u{11ee0}', '\u{11ef2}', WC_ALetter), ('\u{11ef3}', '\u{11ef6}', WC_Extend),
+ ('\u{12000}', '\u{12399}', WC_ALetter), ('\u{12400}', '\u{1246e}', WC_ALetter),
+ ('\u{12480}', '\u{12543}', WC_ALetter), ('\u{13000}', '\u{1342e}', WC_ALetter),
+ ('\u{13430}', '\u{13438}', WC_Format), ('\u{14400}', '\u{14646}', WC_ALetter), ('\u{16800}',
+ '\u{16a38}', WC_ALetter), ('\u{16a40}', '\u{16a5e}', WC_ALetter), ('\u{16a60}', '\u{16a69}',
+ WC_Numeric), ('\u{16ad0}', '\u{16aed}', WC_ALetter), ('\u{16af0}', '\u{16af4}', WC_Extend),
+ ('\u{16b00}', '\u{16b2f}', WC_ALetter), ('\u{16b30}', '\u{16b36}', WC_Extend), ('\u{16b40}',
+ '\u{16b43}', WC_ALetter), ('\u{16b50}', '\u{16b59}', WC_Numeric), ('\u{16b63}', '\u{16b77}',
+ WC_ALetter), ('\u{16b7d}', '\u{16b8f}', WC_ALetter), ('\u{16e40}', '\u{16e7f}', WC_ALetter),
+ ('\u{16f00}', '\u{16f4a}', WC_ALetter), ('\u{16f4f}', '\u{16f4f}', WC_Extend), ('\u{16f50}',
+ '\u{16f50}', WC_ALetter), ('\u{16f51}', '\u{16f87}', WC_Extend), ('\u{16f8f}', '\u{16f92}',
+ WC_Extend), ('\u{16f93}', '\u{16f9f}', WC_ALetter), ('\u{16fe0}', '\u{16fe1}', WC_ALetter),
+ ('\u{16fe3}', '\u{16fe3}', WC_ALetter), ('\u{1b000}', '\u{1b000}', WC_Katakana),
+ ('\u{1b164}', '\u{1b167}', WC_Katakana), ('\u{1bc00}', '\u{1bc6a}', WC_ALetter),
+ ('\u{1bc70}', '\u{1bc7c}', WC_ALetter), ('\u{1bc80}', '\u{1bc88}', WC_ALetter),
+ ('\u{1bc90}', '\u{1bc99}', WC_ALetter), ('\u{1bc9d}', '\u{1bc9e}', WC_Extend), ('\u{1bca0}',
+ '\u{1bca3}', WC_Format), ('\u{1d165}', '\u{1d169}', WC_Extend), ('\u{1d16d}', '\u{1d172}',
+ WC_Extend), ('\u{1d173}', '\u{1d17a}', WC_Format), ('\u{1d17b}', '\u{1d182}', WC_Extend),
+ ('\u{1d185}', '\u{1d18b}', WC_Extend), ('\u{1d1aa}', '\u{1d1ad}', WC_Extend), ('\u{1d242}',
+ '\u{1d244}', WC_Extend), ('\u{1d400}', '\u{1d454}', WC_ALetter), ('\u{1d456}', '\u{1d49c}',
+ WC_ALetter), ('\u{1d49e}', '\u{1d49f}', WC_ALetter), ('\u{1d4a2}', '\u{1d4a2}', WC_ALetter),
+ ('\u{1d4a5}', '\u{1d4a6}', WC_ALetter), ('\u{1d4a9}', '\u{1d4ac}', WC_ALetter),
+ ('\u{1d4ae}', '\u{1d4b9}', WC_ALetter), ('\u{1d4bb}', '\u{1d4bb}', WC_ALetter),
+ ('\u{1d4bd}', '\u{1d4c3}', WC_ALetter), ('\u{1d4c5}', '\u{1d505}', WC_ALetter),
+ ('\u{1d507}', '\u{1d50a}', WC_ALetter), ('\u{1d50d}', '\u{1d514}', WC_ALetter),
+ ('\u{1d516}', '\u{1d51c}', WC_ALetter), ('\u{1d51e}', '\u{1d539}', WC_ALetter),
+ ('\u{1d53b}', '\u{1d53e}', WC_ALetter), ('\u{1d540}', '\u{1d544}', WC_ALetter),
+ ('\u{1d546}', '\u{1d546}', WC_ALetter), ('\u{1d54a}', '\u{1d550}', WC_ALetter),
+ ('\u{1d552}', '\u{1d6a5}', WC_ALetter), ('\u{1d6a8}', '\u{1d6c0}', WC_ALetter),
+ ('\u{1d6c2}', '\u{1d6da}', WC_ALetter), ('\u{1d6dc}', '\u{1d6fa}', WC_ALetter),
+ ('\u{1d6fc}', '\u{1d714}', WC_ALetter), ('\u{1d716}', '\u{1d734}', WC_ALetter),
+ ('\u{1d736}', '\u{1d74e}', WC_ALetter), ('\u{1d750}', '\u{1d76e}', WC_ALetter),
+ ('\u{1d770}', '\u{1d788}', WC_ALetter), ('\u{1d78a}', '\u{1d7a8}', WC_ALetter),
+ ('\u{1d7aa}', '\u{1d7c2}', WC_ALetter), ('\u{1d7c4}', '\u{1d7cb}', WC_ALetter),
+ ('\u{1d7ce}', '\u{1d7ff}', WC_Numeric), ('\u{1da00}', '\u{1da36}', WC_Extend), ('\u{1da3b}',
+ '\u{1da6c}', WC_Extend), ('\u{1da75}', '\u{1da75}', WC_Extend), ('\u{1da84}', '\u{1da84}',
+ WC_Extend), ('\u{1da9b}', '\u{1da9f}', WC_Extend), ('\u{1daa1}', '\u{1daaf}', WC_Extend),
+ ('\u{1e000}', '\u{1e006}', WC_Extend), ('\u{1e008}', '\u{1e018}', WC_Extend), ('\u{1e01b}',
+ '\u{1e021}', WC_Extend), ('\u{1e023}', '\u{1e024}', WC_Extend), ('\u{1e026}', '\u{1e02a}',
+ WC_Extend), ('\u{1e100}', '\u{1e12c}', WC_ALetter), ('\u{1e130}', '\u{1e136}', WC_Extend),
+ ('\u{1e137}', '\u{1e13d}', WC_ALetter), ('\u{1e140}', '\u{1e149}', WC_Numeric),
+ ('\u{1e14e}', '\u{1e14e}', WC_ALetter), ('\u{1e2c0}', '\u{1e2eb}', WC_ALetter),
+ ('\u{1e2ec}', '\u{1e2ef}', WC_Extend), ('\u{1e2f0}', '\u{1e2f9}', WC_Numeric), ('\u{1e800}',
+ '\u{1e8c4}', WC_ALetter), ('\u{1e8d0}', '\u{1e8d6}', WC_Extend), ('\u{1e900}', '\u{1e943}',
+ WC_ALetter), ('\u{1e944}', '\u{1e94a}', WC_Extend), ('\u{1e94b}', '\u{1e94b}', WC_ALetter),
+ ('\u{1e950}', '\u{1e959}', WC_Numeric), ('\u{1ee00}', '\u{1ee03}', WC_ALetter),
+ ('\u{1ee05}', '\u{1ee1f}', WC_ALetter), ('\u{1ee21}', '\u{1ee22}', WC_ALetter),
+ ('\u{1ee24}', '\u{1ee24}', WC_ALetter), ('\u{1ee27}', '\u{1ee27}', WC_ALetter),
+ ('\u{1ee29}', '\u{1ee32}', WC_ALetter), ('\u{1ee34}', '\u{1ee37}', WC_ALetter),
+ ('\u{1ee39}', '\u{1ee39}', WC_ALetter), ('\u{1ee3b}', '\u{1ee3b}', WC_ALetter),
+ ('\u{1ee42}', '\u{1ee42}', WC_ALetter), ('\u{1ee47}', '\u{1ee47}', WC_ALetter),
+ ('\u{1ee49}', '\u{1ee49}', WC_ALetter), ('\u{1ee4b}', '\u{1ee4b}', WC_ALetter),
+ ('\u{1ee4d}', '\u{1ee4f}', WC_ALetter), ('\u{1ee51}', '\u{1ee52}', WC_ALetter),
+ ('\u{1ee54}', '\u{1ee54}', WC_ALetter), ('\u{1ee57}', '\u{1ee57}', WC_ALetter),
+ ('\u{1ee59}', '\u{1ee59}', WC_ALetter), ('\u{1ee5b}', '\u{1ee5b}', WC_ALetter),
+ ('\u{1ee5d}', '\u{1ee5d}', WC_ALetter), ('\u{1ee5f}', '\u{1ee5f}', WC_ALetter),
+ ('\u{1ee61}', '\u{1ee62}', WC_ALetter), ('\u{1ee64}', '\u{1ee64}', WC_ALetter),
+ ('\u{1ee67}', '\u{1ee6a}', WC_ALetter), ('\u{1ee6c}', '\u{1ee72}', WC_ALetter),
+ ('\u{1ee74}', '\u{1ee77}', WC_ALetter), ('\u{1ee79}', '\u{1ee7c}', WC_ALetter),
+ ('\u{1ee7e}', '\u{1ee7e}', WC_ALetter), ('\u{1ee80}', '\u{1ee89}', WC_ALetter),
+ ('\u{1ee8b}', '\u{1ee9b}', WC_ALetter), ('\u{1eea1}', '\u{1eea3}', WC_ALetter),
+ ('\u{1eea5}', '\u{1eea9}', WC_ALetter), ('\u{1eeab}', '\u{1eebb}', WC_ALetter),
+ ('\u{1f130}', '\u{1f149}', WC_ALetter), ('\u{1f150}', '\u{1f169}', WC_ALetter),
+ ('\u{1f170}', '\u{1f189}', WC_ALetter), ('\u{1f1e6}', '\u{1f1ff}', WC_Regional_Indicator),
+ ('\u{1f3fb}', '\u{1f3ff}', WC_Extend), ('\u{e0001}', '\u{e0001}', WC_Format), ('\u{e0020}',
+ '\u{e007f}', WC_Extend), ('\u{e0100}', '\u{e01ef}', WC_Extend)
+ ];
+
+}
+pub mod emoji {
+ use core::result::Result::{Ok, Err};
+
+ pub use self::EmojiCat::*;
+
+ #[allow(non_camel_case_types)]
+ #[derive(Clone, Copy, PartialEq, Eq, Debug)]
+ pub enum EmojiCat {
+ EC_Any,
+ EC_Extended_Pictographic,
+ }
+
+ fn bsearch_range_value_table(c: char, r: &'static [(char, char, EmojiCat)]) -> EmojiCat {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ match r.binary_search_by(|&(lo, hi, _)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }) {
+ Ok(idx) => {
+ let (_, _, cat) = r[idx];
+ cat
+ }
+ Err(_) => EC_Any
+ }
+ }
+
+ pub fn emoji_category(c: char) -> EmojiCat {
+ bsearch_range_value_table(c, emoji_cat_table)
+ }
+
+ const emoji_cat_table: &'static [(char, char, EmojiCat)] = &[
+ ('\u{a9}', '\u{a9}', EC_Extended_Pictographic), ('\u{ae}', '\u{ae}',
+ EC_Extended_Pictographic), ('\u{203c}', '\u{203c}', EC_Extended_Pictographic), ('\u{2049}',
+ '\u{2049}', EC_Extended_Pictographic), ('\u{2122}', '\u{2122}', EC_Extended_Pictographic),
+ ('\u{2139}', '\u{2139}', EC_Extended_Pictographic), ('\u{2194}', '\u{2199}',
+ EC_Extended_Pictographic), ('\u{21a9}', '\u{21aa}', EC_Extended_Pictographic), ('\u{231a}',
+ '\u{231b}', EC_Extended_Pictographic), ('\u{2328}', '\u{2328}', EC_Extended_Pictographic),
+ ('\u{2388}', '\u{2388}', EC_Extended_Pictographic), ('\u{23cf}', '\u{23cf}',
+ EC_Extended_Pictographic), ('\u{23e9}', '\u{23f3}', EC_Extended_Pictographic), ('\u{23f8}',
+ '\u{23fa}', EC_Extended_Pictographic), ('\u{24c2}', '\u{24c2}', EC_Extended_Pictographic),
+ ('\u{25aa}', '\u{25ab}', EC_Extended_Pictographic), ('\u{25b6}', '\u{25b6}',
+ EC_Extended_Pictographic), ('\u{25c0}', '\u{25c0}', EC_Extended_Pictographic), ('\u{25fb}',
+ '\u{25fe}', EC_Extended_Pictographic), ('\u{2600}', '\u{2605}', EC_Extended_Pictographic),
+ ('\u{2607}', '\u{2612}', EC_Extended_Pictographic), ('\u{2614}', '\u{2685}',
+ EC_Extended_Pictographic), ('\u{2690}', '\u{2705}', EC_Extended_Pictographic), ('\u{2708}',
+ '\u{2712}', EC_Extended_Pictographic), ('\u{2714}', '\u{2714}', EC_Extended_Pictographic),
+ ('\u{2716}', '\u{2716}', EC_Extended_Pictographic), ('\u{271d}', '\u{271d}',
+ EC_Extended_Pictographic), ('\u{2721}', '\u{2721}', EC_Extended_Pictographic), ('\u{2728}',
+ '\u{2728}', EC_Extended_Pictographic), ('\u{2733}', '\u{2734}', EC_Extended_Pictographic),
+ ('\u{2744}', '\u{2744}', EC_Extended_Pictographic), ('\u{2747}', '\u{2747}',
+ EC_Extended_Pictographic), ('\u{274c}', '\u{274c}', EC_Extended_Pictographic), ('\u{274e}',
+ '\u{274e}', EC_Extended_Pictographic), ('\u{2753}', '\u{2755}', EC_Extended_Pictographic),
+ ('\u{2757}', '\u{2757}', EC_Extended_Pictographic), ('\u{2763}', '\u{2767}',
+ EC_Extended_Pictographic), ('\u{2795}', '\u{2797}', EC_Extended_Pictographic), ('\u{27a1}',
+ '\u{27a1}', EC_Extended_Pictographic), ('\u{27b0}', '\u{27b0}', EC_Extended_Pictographic),
+ ('\u{27bf}', '\u{27bf}', EC_Extended_Pictographic), ('\u{2934}', '\u{2935}',
+ EC_Extended_Pictographic), ('\u{2b05}', '\u{2b07}', EC_Extended_Pictographic), ('\u{2b1b}',
+ '\u{2b1c}', EC_Extended_Pictographic), ('\u{2b50}', '\u{2b50}', EC_Extended_Pictographic),
+ ('\u{2b55}', '\u{2b55}', EC_Extended_Pictographic), ('\u{3030}', '\u{3030}',
+ EC_Extended_Pictographic), ('\u{303d}', '\u{303d}', EC_Extended_Pictographic), ('\u{3297}',
+ '\u{3297}', EC_Extended_Pictographic), ('\u{3299}', '\u{3299}', EC_Extended_Pictographic),
+ ('\u{1f000}', '\u{1f0ff}', EC_Extended_Pictographic), ('\u{1f10d}', '\u{1f10f}',
+ EC_Extended_Pictographic), ('\u{1f12f}', '\u{1f12f}', EC_Extended_Pictographic),
+ ('\u{1f16c}', '\u{1f171}', EC_Extended_Pictographic), ('\u{1f17e}', '\u{1f17f}',
+ EC_Extended_Pictographic), ('\u{1f18e}', '\u{1f18e}', EC_Extended_Pictographic),
+ ('\u{1f191}', '\u{1f19a}', EC_Extended_Pictographic), ('\u{1f1ad}', '\u{1f1e5}',
+ EC_Extended_Pictographic), ('\u{1f201}', '\u{1f20f}', EC_Extended_Pictographic),
+ ('\u{1f21a}', '\u{1f21a}', EC_Extended_Pictographic), ('\u{1f22f}', '\u{1f22f}',
+ EC_Extended_Pictographic), ('\u{1f232}', '\u{1f23a}', EC_Extended_Pictographic),
+ ('\u{1f23c}', '\u{1f23f}', EC_Extended_Pictographic), ('\u{1f249}', '\u{1f3fa}',
+ EC_Extended_Pictographic), ('\u{1f400}', '\u{1f53d}', EC_Extended_Pictographic),
+ ('\u{1f546}', '\u{1f64f}', EC_Extended_Pictographic), ('\u{1f680}', '\u{1f6ff}',
+ EC_Extended_Pictographic), ('\u{1f774}', '\u{1f77f}', EC_Extended_Pictographic),
+ ('\u{1f7d5}', '\u{1f7ff}', EC_Extended_Pictographic), ('\u{1f80c}', '\u{1f80f}',
+ EC_Extended_Pictographic), ('\u{1f848}', '\u{1f84f}', EC_Extended_Pictographic),
+ ('\u{1f85a}', '\u{1f85f}', EC_Extended_Pictographic), ('\u{1f888}', '\u{1f88f}',
+ EC_Extended_Pictographic), ('\u{1f8ae}', '\u{1f8ff}', EC_Extended_Pictographic),
+ ('\u{1f90c}', '\u{1f93a}', EC_Extended_Pictographic), ('\u{1f93c}', '\u{1f945}',
+ EC_Extended_Pictographic), ('\u{1f947}', '\u{1fffd}', EC_Extended_Pictographic)
+ ];
+
+}
+pub mod sentence {
+ use core::result::Result::{Ok, Err};
+
+ pub use self::SentenceCat::*;
+
+ #[allow(non_camel_case_types)]
+ #[derive(Clone, Copy, PartialEq, Eq, Debug)]
+ pub enum SentenceCat {
+ SC_ATerm,
+ SC_Any,
+ SC_CR,
+ SC_Close,
+ SC_Extend,
+ SC_Format,
+ SC_LF,
+ SC_Lower,
+ SC_Numeric,
+ SC_OLetter,
+ SC_SContinue,
+ SC_STerm,
+ SC_Sep,
+ SC_Sp,
+ SC_Upper,
+ }
+
+ fn bsearch_range_value_table(c: char, r: &'static [(char, char, SentenceCat)]) -> SentenceCat {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ match r.binary_search_by(|&(lo, hi, _)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }) {
+ Ok(idx) => {
+ let (_, _, cat) = r[idx];
+ cat
+ }
+ Err(_) => SC_Any
+ }
+ }
+
+ pub fn sentence_category(c: char) -> SentenceCat {
+ bsearch_range_value_table(c, sentence_cat_table)
+ }
+
+ const sentence_cat_table: &'static [(char, char, SentenceCat)] = &[
+ ('\u{9}', '\u{9}', SC_Sp), ('\u{a}', '\u{a}', SC_LF), ('\u{b}', '\u{c}', SC_Sp), ('\u{d}',
+ '\u{d}', SC_CR), ('\u{20}', '\u{20}', SC_Sp), ('\u{21}', '\u{21}', SC_STerm), ('\u{22}',
+ '\u{22}', SC_Close), ('\u{27}', '\u{29}', SC_Close), ('\u{2c}', '\u{2d}', SC_SContinue),
+ ('\u{2e}', '\u{2e}', SC_ATerm), ('\u{30}', '\u{39}', SC_Numeric), ('\u{3a}', '\u{3a}',
+ SC_SContinue), ('\u{3f}', '\u{3f}', SC_STerm), ('\u{41}', '\u{5a}', SC_Upper), ('\u{5b}',
+ '\u{5b}', SC_Close), ('\u{5d}', '\u{5d}', SC_Close), ('\u{61}', '\u{7a}', SC_Lower),
+ ('\u{7b}', '\u{7b}', SC_Close), ('\u{7d}', '\u{7d}', SC_Close), ('\u{85}', '\u{85}',
+ SC_Sep), ('\u{a0}', '\u{a0}', SC_Sp), ('\u{aa}', '\u{aa}', SC_Lower), ('\u{ab}', '\u{ab}',
+ SC_Close), ('\u{ad}', '\u{ad}', SC_Format), ('\u{b5}', '\u{b5}', SC_Lower), ('\u{ba}',
+ '\u{ba}', SC_Lower), ('\u{bb}', '\u{bb}', SC_Close), ('\u{c0}', '\u{d6}', SC_Upper),
+ ('\u{d8}', '\u{de}', SC_Upper), ('\u{df}', '\u{f6}', SC_Lower), ('\u{f8}', '\u{ff}',
+ SC_Lower), ('\u{100}', '\u{100}', SC_Upper), ('\u{101}', '\u{101}', SC_Lower), ('\u{102}',
+ '\u{102}', SC_Upper), ('\u{103}', '\u{103}', SC_Lower), ('\u{104}', '\u{104}', SC_Upper),
+ ('\u{105}', '\u{105}', SC_Lower), ('\u{106}', '\u{106}', SC_Upper), ('\u{107}', '\u{107}',
+ SC_Lower), ('\u{108}', '\u{108}', SC_Upper), ('\u{109}', '\u{109}', SC_Lower), ('\u{10a}',
+ '\u{10a}', SC_Upper), ('\u{10b}', '\u{10b}', SC_Lower), ('\u{10c}', '\u{10c}', SC_Upper),
+ ('\u{10d}', '\u{10d}', SC_Lower), ('\u{10e}', '\u{10e}', SC_Upper), ('\u{10f}', '\u{10f}',
+ SC_Lower), ('\u{110}', '\u{110}', SC_Upper), ('\u{111}', '\u{111}', SC_Lower), ('\u{112}',
+ '\u{112}', SC_Upper), ('\u{113}', '\u{113}', SC_Lower), ('\u{114}', '\u{114}', SC_Upper),
+ ('\u{115}', '\u{115}', SC_Lower), ('\u{116}', '\u{116}', SC_Upper), ('\u{117}', '\u{117}',
+ SC_Lower), ('\u{118}', '\u{118}', SC_Upper), ('\u{119}', '\u{119}', SC_Lower), ('\u{11a}',
+ '\u{11a}', SC_Upper), ('\u{11b}', '\u{11b}', SC_Lower), ('\u{11c}', '\u{11c}', SC_Upper),
+ ('\u{11d}', '\u{11d}', SC_Lower), ('\u{11e}', '\u{11e}', SC_Upper), ('\u{11f}', '\u{11f}',
+ SC_Lower), ('\u{120}', '\u{120}', SC_Upper), ('\u{121}', '\u{121}', SC_Lower), ('\u{122}',
+ '\u{122}', SC_Upper), ('\u{123}', '\u{123}', SC_Lower), ('\u{124}', '\u{124}', SC_Upper),
+ ('\u{125}', '\u{125}', SC_Lower), ('\u{126}', '\u{126}', SC_Upper), ('\u{127}', '\u{127}',
+ SC_Lower), ('\u{128}', '\u{128}', SC_Upper), ('\u{129}', '\u{129}', SC_Lower), ('\u{12a}',
+ '\u{12a}', SC_Upper), ('\u{12b}', '\u{12b}', SC_Lower), ('\u{12c}', '\u{12c}', SC_Upper),
+ ('\u{12d}', '\u{12d}', SC_Lower), ('\u{12e}', '\u{12e}', SC_Upper), ('\u{12f}', '\u{12f}',
+ SC_Lower), ('\u{130}', '\u{130}', SC_Upper), ('\u{131}', '\u{131}', SC_Lower), ('\u{132}',
+ '\u{132}', SC_Upper), ('\u{133}', '\u{133}', SC_Lower), ('\u{134}', '\u{134}', SC_Upper),
+ ('\u{135}', '\u{135}', SC_Lower), ('\u{136}', '\u{136}', SC_Upper), ('\u{137}', '\u{138}',
+ SC_Lower), ('\u{139}', '\u{139}', SC_Upper), ('\u{13a}', '\u{13a}', SC_Lower), ('\u{13b}',
+ '\u{13b}', SC_Upper), ('\u{13c}', '\u{13c}', SC_Lower), ('\u{13d}', '\u{13d}', SC_Upper),
+ ('\u{13e}', '\u{13e}', SC_Lower), ('\u{13f}', '\u{13f}', SC_Upper), ('\u{140}', '\u{140}',
+ SC_Lower), ('\u{141}', '\u{141}', SC_Upper), ('\u{142}', '\u{142}', SC_Lower), ('\u{143}',
+ '\u{143}', SC_Upper), ('\u{144}', '\u{144}', SC_Lower), ('\u{145}', '\u{145}', SC_Upper),
+ ('\u{146}', '\u{146}', SC_Lower), ('\u{147}', '\u{147}', SC_Upper), ('\u{148}', '\u{149}',
+ SC_Lower), ('\u{14a}', '\u{14a}', SC_Upper), ('\u{14b}', '\u{14b}', SC_Lower), ('\u{14c}',
+ '\u{14c}', SC_Upper), ('\u{14d}', '\u{14d}', SC_Lower), ('\u{14e}', '\u{14e}', SC_Upper),
+ ('\u{14f}', '\u{14f}', SC_Lower), ('\u{150}', '\u{150}', SC_Upper), ('\u{151}', '\u{151}',
+ SC_Lower), ('\u{152}', '\u{152}', SC_Upper), ('\u{153}', '\u{153}', SC_Lower), ('\u{154}',
+ '\u{154}', SC_Upper), ('\u{155}', '\u{155}', SC_Lower), ('\u{156}', '\u{156}', SC_Upper),
+ ('\u{157}', '\u{157}', SC_Lower), ('\u{158}', '\u{158}', SC_Upper), ('\u{159}', '\u{159}',
+ SC_Lower), ('\u{15a}', '\u{15a}', SC_Upper), ('\u{15b}', '\u{15b}', SC_Lower), ('\u{15c}',
+ '\u{15c}', SC_Upper), ('\u{15d}', '\u{15d}', SC_Lower), ('\u{15e}', '\u{15e}', SC_Upper),
+ ('\u{15f}', '\u{15f}', SC_Lower), ('\u{160}', '\u{160}', SC_Upper), ('\u{161}', '\u{161}',
+ SC_Lower), ('\u{162}', '\u{162}', SC_Upper), ('\u{163}', '\u{163}', SC_Lower), ('\u{164}',
+ '\u{164}', SC_Upper), ('\u{165}', '\u{165}', SC_Lower), ('\u{166}', '\u{166}', SC_Upper),
+ ('\u{167}', '\u{167}', SC_Lower), ('\u{168}', '\u{168}', SC_Upper), ('\u{169}', '\u{169}',
+ SC_Lower), ('\u{16a}', '\u{16a}', SC_Upper), ('\u{16b}', '\u{16b}', SC_Lower), ('\u{16c}',
+ '\u{16c}', SC_Upper), ('\u{16d}', '\u{16d}', SC_Lower), ('\u{16e}', '\u{16e}', SC_Upper),
+ ('\u{16f}', '\u{16f}', SC_Lower), ('\u{170}', '\u{170}', SC_Upper), ('\u{171}', '\u{171}',
+ SC_Lower), ('\u{172}', '\u{172}', SC_Upper), ('\u{173}', '\u{173}', SC_Lower), ('\u{174}',
+ '\u{174}', SC_Upper), ('\u{175}', '\u{175}', SC_Lower), ('\u{176}', '\u{176}', SC_Upper),
+ ('\u{177}', '\u{177}', SC_Lower), ('\u{178}', '\u{179}', SC_Upper), ('\u{17a}', '\u{17a}',
+ SC_Lower), ('\u{17b}', '\u{17b}', SC_Upper), ('\u{17c}', '\u{17c}', SC_Lower), ('\u{17d}',
+ '\u{17d}', SC_Upper), ('\u{17e}', '\u{180}', SC_Lower), ('\u{181}', '\u{182}', SC_Upper),
+ ('\u{183}', '\u{183}', SC_Lower), ('\u{184}', '\u{184}', SC_Upper), ('\u{185}', '\u{185}',
+ SC_Lower), ('\u{186}', '\u{187}', SC_Upper), ('\u{188}', '\u{188}', SC_Lower), ('\u{189}',
+ '\u{18b}', SC_Upper), ('\u{18c}', '\u{18d}', SC_Lower), ('\u{18e}', '\u{191}', SC_Upper),
+ ('\u{192}', '\u{192}', SC_Lower), ('\u{193}', '\u{194}', SC_Upper), ('\u{195}', '\u{195}',
+ SC_Lower), ('\u{196}', '\u{198}', SC_Upper), ('\u{199}', '\u{19b}', SC_Lower), ('\u{19c}',
+ '\u{19d}', SC_Upper), ('\u{19e}', '\u{19e}', SC_Lower), ('\u{19f}', '\u{1a0}', SC_Upper),
+ ('\u{1a1}', '\u{1a1}', SC_Lower), ('\u{1a2}', '\u{1a2}', SC_Upper), ('\u{1a3}', '\u{1a3}',
+ SC_Lower), ('\u{1a4}', '\u{1a4}', SC_Upper), ('\u{1a5}', '\u{1a5}', SC_Lower), ('\u{1a6}',
+ '\u{1a7}', SC_Upper), ('\u{1a8}', '\u{1a8}', SC_Lower), ('\u{1a9}', '\u{1a9}', SC_Upper),
+ ('\u{1aa}', '\u{1ab}', SC_Lower), ('\u{1ac}', '\u{1ac}', SC_Upper), ('\u{1ad}', '\u{1ad}',
+ SC_Lower), ('\u{1ae}', '\u{1af}', SC_Upper), ('\u{1b0}', '\u{1b0}', SC_Lower), ('\u{1b1}',
+ '\u{1b3}', SC_Upper), ('\u{1b4}', '\u{1b4}', SC_Lower), ('\u{1b5}', '\u{1b5}', SC_Upper),
+ ('\u{1b6}', '\u{1b6}', SC_Lower), ('\u{1b7}', '\u{1b8}', SC_Upper), ('\u{1b9}', '\u{1ba}',
+ SC_Lower), ('\u{1bb}', '\u{1bb}', SC_OLetter), ('\u{1bc}', '\u{1bc}', SC_Upper), ('\u{1bd}',
+ '\u{1bf}', SC_Lower), ('\u{1c0}', '\u{1c3}', SC_OLetter), ('\u{1c4}', '\u{1c5}', SC_Upper),
+ ('\u{1c6}', '\u{1c6}', SC_Lower), ('\u{1c7}', '\u{1c8}', SC_Upper), ('\u{1c9}', '\u{1c9}',
+ SC_Lower), ('\u{1ca}', '\u{1cb}', SC_Upper), ('\u{1cc}', '\u{1cc}', SC_Lower), ('\u{1cd}',
+ '\u{1cd}', SC_Upper), ('\u{1ce}', '\u{1ce}', SC_Lower), ('\u{1cf}', '\u{1cf}', SC_Upper),
+ ('\u{1d0}', '\u{1d0}', SC_Lower), ('\u{1d1}', '\u{1d1}', SC_Upper), ('\u{1d2}', '\u{1d2}',
+ SC_Lower), ('\u{1d3}', '\u{1d3}', SC_Upper), ('\u{1d4}', '\u{1d4}', SC_Lower), ('\u{1d5}',
+ '\u{1d5}', SC_Upper), ('\u{1d6}', '\u{1d6}', SC_Lower), ('\u{1d7}', '\u{1d7}', SC_Upper),
+ ('\u{1d8}', '\u{1d8}', SC_Lower), ('\u{1d9}', '\u{1d9}', SC_Upper), ('\u{1da}', '\u{1da}',
+ SC_Lower), ('\u{1db}', '\u{1db}', SC_Upper), ('\u{1dc}', '\u{1dd}', SC_Lower), ('\u{1de}',
+ '\u{1de}', SC_Upper), ('\u{1df}', '\u{1df}', SC_Lower), ('\u{1e0}', '\u{1e0}', SC_Upper),
+ ('\u{1e1}', '\u{1e1}', SC_Lower), ('\u{1e2}', '\u{1e2}', SC_Upper), ('\u{1e3}', '\u{1e3}',
+ SC_Lower), ('\u{1e4}', '\u{1e4}', SC_Upper), ('\u{1e5}', '\u{1e5}', SC_Lower), ('\u{1e6}',
+ '\u{1e6}', SC_Upper), ('\u{1e7}', '\u{1e7}', SC_Lower), ('\u{1e8}', '\u{1e8}', SC_Upper),
+ ('\u{1e9}', '\u{1e9}', SC_Lower), ('\u{1ea}', '\u{1ea}', SC_Upper), ('\u{1eb}', '\u{1eb}',
+ SC_Lower), ('\u{1ec}', '\u{1ec}', SC_Upper), ('\u{1ed}', '\u{1ed}', SC_Lower), ('\u{1ee}',
+ '\u{1ee}', SC_Upper), ('\u{1ef}', '\u{1f0}', SC_Lower), ('\u{1f1}', '\u{1f2}', SC_Upper),
+ ('\u{1f3}', '\u{1f3}', SC_Lower), ('\u{1f4}', '\u{1f4}', SC_Upper), ('\u{1f5}', '\u{1f5}',
+ SC_Lower), ('\u{1f6}', '\u{1f8}', SC_Upper), ('\u{1f9}', '\u{1f9}', SC_Lower), ('\u{1fa}',
+ '\u{1fa}', SC_Upper), ('\u{1fb}', '\u{1fb}', SC_Lower), ('\u{1fc}', '\u{1fc}', SC_Upper),
+ ('\u{1fd}', '\u{1fd}', SC_Lower), ('\u{1fe}', '\u{1fe}', SC_Upper), ('\u{1ff}', '\u{1ff}',
+ SC_Lower), ('\u{200}', '\u{200}', SC_Upper), ('\u{201}', '\u{201}', SC_Lower), ('\u{202}',
+ '\u{202}', SC_Upper), ('\u{203}', '\u{203}', SC_Lower), ('\u{204}', '\u{204}', SC_Upper),
+ ('\u{205}', '\u{205}', SC_Lower), ('\u{206}', '\u{206}', SC_Upper), ('\u{207}', '\u{207}',
+ SC_Lower), ('\u{208}', '\u{208}', SC_Upper), ('\u{209}', '\u{209}', SC_Lower), ('\u{20a}',
+ '\u{20a}', SC_Upper), ('\u{20b}', '\u{20b}', SC_Lower), ('\u{20c}', '\u{20c}', SC_Upper),
+ ('\u{20d}', '\u{20d}', SC_Lower), ('\u{20e}', '\u{20e}', SC_Upper), ('\u{20f}', '\u{20f}',
+ SC_Lower), ('\u{210}', '\u{210}', SC_Upper), ('\u{211}', '\u{211}', SC_Lower), ('\u{212}',
+ '\u{212}', SC_Upper), ('\u{213}', '\u{213}', SC_Lower), ('\u{214}', '\u{214}', SC_Upper),
+ ('\u{215}', '\u{215}', SC_Lower), ('\u{216}', '\u{216}', SC_Upper), ('\u{217}', '\u{217}',
+ SC_Lower), ('\u{218}', '\u{218}', SC_Upper), ('\u{219}', '\u{219}', SC_Lower), ('\u{21a}',
+ '\u{21a}', SC_Upper), ('\u{21b}', '\u{21b}', SC_Lower), ('\u{21c}', '\u{21c}', SC_Upper),
+ ('\u{21d}', '\u{21d}', SC_Lower), ('\u{21e}', '\u{21e}', SC_Upper), ('\u{21f}', '\u{21f}',
+ SC_Lower), ('\u{220}', '\u{220}', SC_Upper), ('\u{221}', '\u{221}', SC_Lower), ('\u{222}',
+ '\u{222}', SC_Upper), ('\u{223}', '\u{223}', SC_Lower), ('\u{224}', '\u{224}', SC_Upper),
+ ('\u{225}', '\u{225}', SC_Lower), ('\u{226}', '\u{226}', SC_Upper), ('\u{227}', '\u{227}',
+ SC_Lower), ('\u{228}', '\u{228}', SC_Upper), ('\u{229}', '\u{229}', SC_Lower), ('\u{22a}',
+ '\u{22a}', SC_Upper), ('\u{22b}', '\u{22b}', SC_Lower), ('\u{22c}', '\u{22c}', SC_Upper),
+ ('\u{22d}', '\u{22d}', SC_Lower), ('\u{22e}', '\u{22e}', SC_Upper), ('\u{22f}', '\u{22f}',
+ SC_Lower), ('\u{230}', '\u{230}', SC_Upper), ('\u{231}', '\u{231}', SC_Lower), ('\u{232}',
+ '\u{232}', SC_Upper), ('\u{233}', '\u{239}', SC_Lower), ('\u{23a}', '\u{23b}', SC_Upper),
+ ('\u{23c}', '\u{23c}', SC_Lower), ('\u{23d}', '\u{23e}', SC_Upper), ('\u{23f}', '\u{240}',
+ SC_Lower), ('\u{241}', '\u{241}', SC_Upper), ('\u{242}', '\u{242}', SC_Lower), ('\u{243}',
+ '\u{246}', SC_Upper), ('\u{247}', '\u{247}', SC_Lower), ('\u{248}', '\u{248}', SC_Upper),
+ ('\u{249}', '\u{249}', SC_Lower), ('\u{24a}', '\u{24a}', SC_Upper), ('\u{24b}', '\u{24b}',
+ SC_Lower), ('\u{24c}', '\u{24c}', SC_Upper), ('\u{24d}', '\u{24d}', SC_Lower), ('\u{24e}',
+ '\u{24e}', SC_Upper), ('\u{24f}', '\u{293}', SC_Lower), ('\u{294}', '\u{294}', SC_OLetter),
+ ('\u{295}', '\u{2b8}', SC_Lower), ('\u{2b9}', '\u{2bf}', SC_OLetter), ('\u{2c0}', '\u{2c1}',
+ SC_Lower), ('\u{2c6}', '\u{2d1}', SC_OLetter), ('\u{2e0}', '\u{2e4}', SC_Lower), ('\u{2ec}',
+ '\u{2ec}', SC_OLetter), ('\u{2ee}', '\u{2ee}', SC_OLetter), ('\u{300}', '\u{36f}',
+ SC_Extend), ('\u{370}', '\u{370}', SC_Upper), ('\u{371}', '\u{371}', SC_Lower), ('\u{372}',
+ '\u{372}', SC_Upper), ('\u{373}', '\u{373}', SC_Lower), ('\u{374}', '\u{374}', SC_OLetter),
+ ('\u{376}', '\u{376}', SC_Upper), ('\u{377}', '\u{377}', SC_Lower), ('\u{37a}', '\u{37d}',
+ SC_Lower), ('\u{37f}', '\u{37f}', SC_Upper), ('\u{386}', '\u{386}', SC_Upper), ('\u{388}',
+ '\u{38a}', SC_Upper), ('\u{38c}', '\u{38c}', SC_Upper), ('\u{38e}', '\u{38f}', SC_Upper),
+ ('\u{390}', '\u{390}', SC_Lower), ('\u{391}', '\u{3a1}', SC_Upper), ('\u{3a3}', '\u{3ab}',
+ SC_Upper), ('\u{3ac}', '\u{3ce}', SC_Lower), ('\u{3cf}', '\u{3cf}', SC_Upper), ('\u{3d0}',
+ '\u{3d1}', SC_Lower), ('\u{3d2}', '\u{3d4}', SC_Upper), ('\u{3d5}', '\u{3d7}', SC_Lower),
+ ('\u{3d8}', '\u{3d8}', SC_Upper), ('\u{3d9}', '\u{3d9}', SC_Lower), ('\u{3da}', '\u{3da}',
+ SC_Upper), ('\u{3db}', '\u{3db}', SC_Lower), ('\u{3dc}', '\u{3dc}', SC_Upper), ('\u{3dd}',
+ '\u{3dd}', SC_Lower), ('\u{3de}', '\u{3de}', SC_Upper), ('\u{3df}', '\u{3df}', SC_Lower),
+ ('\u{3e0}', '\u{3e0}', SC_Upper), ('\u{3e1}', '\u{3e1}', SC_Lower), ('\u{3e2}', '\u{3e2}',
+ SC_Upper), ('\u{3e3}', '\u{3e3}', SC_Lower), ('\u{3e4}', '\u{3e4}', SC_Upper), ('\u{3e5}',
+ '\u{3e5}', SC_Lower), ('\u{3e6}', '\u{3e6}', SC_Upper), ('\u{3e7}', '\u{3e7}', SC_Lower),
+ ('\u{3e8}', '\u{3e8}', SC_Upper), ('\u{3e9}', '\u{3e9}', SC_Lower), ('\u{3ea}', '\u{3ea}',
+ SC_Upper), ('\u{3eb}', '\u{3eb}', SC_Lower), ('\u{3ec}', '\u{3ec}', SC_Upper), ('\u{3ed}',
+ '\u{3ed}', SC_Lower), ('\u{3ee}', '\u{3ee}', SC_Upper), ('\u{3ef}', '\u{3f3}', SC_Lower),
+ ('\u{3f4}', '\u{3f4}', SC_Upper), ('\u{3f5}', '\u{3f5}', SC_Lower), ('\u{3f7}', '\u{3f7}',
+ SC_Upper), ('\u{3f8}', '\u{3f8}', SC_Lower), ('\u{3f9}', '\u{3fa}', SC_Upper), ('\u{3fb}',
+ '\u{3fc}', SC_Lower), ('\u{3fd}', '\u{42f}', SC_Upper), ('\u{430}', '\u{45f}', SC_Lower),
+ ('\u{460}', '\u{460}', SC_Upper), ('\u{461}', '\u{461}', SC_Lower), ('\u{462}', '\u{462}',
+ SC_Upper), ('\u{463}', '\u{463}', SC_Lower), ('\u{464}', '\u{464}', SC_Upper), ('\u{465}',
+ '\u{465}', SC_Lower), ('\u{466}', '\u{466}', SC_Upper), ('\u{467}', '\u{467}', SC_Lower),
+ ('\u{468}', '\u{468}', SC_Upper), ('\u{469}', '\u{469}', SC_Lower), ('\u{46a}', '\u{46a}',
+ SC_Upper), ('\u{46b}', '\u{46b}', SC_Lower), ('\u{46c}', '\u{46c}', SC_Upper), ('\u{46d}',
+ '\u{46d}', SC_Lower), ('\u{46e}', '\u{46e}', SC_Upper), ('\u{46f}', '\u{46f}', SC_Lower),
+ ('\u{470}', '\u{470}', SC_Upper), ('\u{471}', '\u{471}', SC_Lower), ('\u{472}', '\u{472}',
+ SC_Upper), ('\u{473}', '\u{473}', SC_Lower), ('\u{474}', '\u{474}', SC_Upper), ('\u{475}',
+ '\u{475}', SC_Lower), ('\u{476}', '\u{476}', SC_Upper), ('\u{477}', '\u{477}', SC_Lower),
+ ('\u{478}', '\u{478}', SC_Upper), ('\u{479}', '\u{479}', SC_Lower), ('\u{47a}', '\u{47a}',
+ SC_Upper), ('\u{47b}', '\u{47b}', SC_Lower), ('\u{47c}', '\u{47c}', SC_Upper), ('\u{47d}',
+ '\u{47d}', SC_Lower), ('\u{47e}', '\u{47e}', SC_Upper), ('\u{47f}', '\u{47f}', SC_Lower),
+ ('\u{480}', '\u{480}', SC_Upper), ('\u{481}', '\u{481}', SC_Lower), ('\u{483}', '\u{489}',
+ SC_Extend), ('\u{48a}', '\u{48a}', SC_Upper), ('\u{48b}', '\u{48b}', SC_Lower), ('\u{48c}',
+ '\u{48c}', SC_Upper), ('\u{48d}', '\u{48d}', SC_Lower), ('\u{48e}', '\u{48e}', SC_Upper),
+ ('\u{48f}', '\u{48f}', SC_Lower), ('\u{490}', '\u{490}', SC_Upper), ('\u{491}', '\u{491}',
+ SC_Lower), ('\u{492}', '\u{492}', SC_Upper), ('\u{493}', '\u{493}', SC_Lower), ('\u{494}',
+ '\u{494}', SC_Upper), ('\u{495}', '\u{495}', SC_Lower), ('\u{496}', '\u{496}', SC_Upper),
+ ('\u{497}', '\u{497}', SC_Lower), ('\u{498}', '\u{498}', SC_Upper), ('\u{499}', '\u{499}',
+ SC_Lower), ('\u{49a}', '\u{49a}', SC_Upper), ('\u{49b}', '\u{49b}', SC_Lower), ('\u{49c}',
+ '\u{49c}', SC_Upper), ('\u{49d}', '\u{49d}', SC_Lower), ('\u{49e}', '\u{49e}', SC_Upper),
+ ('\u{49f}', '\u{49f}', SC_Lower), ('\u{4a0}', '\u{4a0}', SC_Upper), ('\u{4a1}', '\u{4a1}',
+ SC_Lower), ('\u{4a2}', '\u{4a2}', SC_Upper), ('\u{4a3}', '\u{4a3}', SC_Lower), ('\u{4a4}',
+ '\u{4a4}', SC_Upper), ('\u{4a5}', '\u{4a5}', SC_Lower), ('\u{4a6}', '\u{4a6}', SC_Upper),
+ ('\u{4a7}', '\u{4a7}', SC_Lower), ('\u{4a8}', '\u{4a8}', SC_Upper), ('\u{4a9}', '\u{4a9}',
+ SC_Lower), ('\u{4aa}', '\u{4aa}', SC_Upper), ('\u{4ab}', '\u{4ab}', SC_Lower), ('\u{4ac}',
+ '\u{4ac}', SC_Upper), ('\u{4ad}', '\u{4ad}', SC_Lower), ('\u{4ae}', '\u{4ae}', SC_Upper),
+ ('\u{4af}', '\u{4af}', SC_Lower), ('\u{4b0}', '\u{4b0}', SC_Upper), ('\u{4b1}', '\u{4b1}',
+ SC_Lower), ('\u{4b2}', '\u{4b2}', SC_Upper), ('\u{4b3}', '\u{4b3}', SC_Lower), ('\u{4b4}',
+ '\u{4b4}', SC_Upper), ('\u{4b5}', '\u{4b5}', SC_Lower), ('\u{4b6}', '\u{4b6}', SC_Upper),
+ ('\u{4b7}', '\u{4b7}', SC_Lower), ('\u{4b8}', '\u{4b8}', SC_Upper), ('\u{4b9}', '\u{4b9}',
+ SC_Lower), ('\u{4ba}', '\u{4ba}', SC_Upper), ('\u{4bb}', '\u{4bb}', SC_Lower), ('\u{4bc}',
+ '\u{4bc}', SC_Upper), ('\u{4bd}', '\u{4bd}', SC_Lower), ('\u{4be}', '\u{4be}', SC_Upper),
+ ('\u{4bf}', '\u{4bf}', SC_Lower), ('\u{4c0}', '\u{4c1}', SC_Upper), ('\u{4c2}', '\u{4c2}',
+ SC_Lower), ('\u{4c3}', '\u{4c3}', SC_Upper), ('\u{4c4}', '\u{4c4}', SC_Lower), ('\u{4c5}',
+ '\u{4c5}', SC_Upper), ('\u{4c6}', '\u{4c6}', SC_Lower), ('\u{4c7}', '\u{4c7}', SC_Upper),
+ ('\u{4c8}', '\u{4c8}', SC_Lower), ('\u{4c9}', '\u{4c9}', SC_Upper), ('\u{4ca}', '\u{4ca}',
+ SC_Lower), ('\u{4cb}', '\u{4cb}', SC_Upper), ('\u{4cc}', '\u{4cc}', SC_Lower), ('\u{4cd}',
+ '\u{4cd}', SC_Upper), ('\u{4ce}', '\u{4cf}', SC_Lower), ('\u{4d0}', '\u{4d0}', SC_Upper),
+ ('\u{4d1}', '\u{4d1}', SC_Lower), ('\u{4d2}', '\u{4d2}', SC_Upper), ('\u{4d3}', '\u{4d3}',
+ SC_Lower), ('\u{4d4}', '\u{4d4}', SC_Upper), ('\u{4d5}', '\u{4d5}', SC_Lower), ('\u{4d6}',
+ '\u{4d6}', SC_Upper), ('\u{4d7}', '\u{4d7}', SC_Lower), ('\u{4d8}', '\u{4d8}', SC_Upper),
+ ('\u{4d9}', '\u{4d9}', SC_Lower), ('\u{4da}', '\u{4da}', SC_Upper), ('\u{4db}', '\u{4db}',
+ SC_Lower), ('\u{4dc}', '\u{4dc}', SC_Upper), ('\u{4dd}', '\u{4dd}', SC_Lower), ('\u{4de}',
+ '\u{4de}', SC_Upper), ('\u{4df}', '\u{4df}', SC_Lower), ('\u{4e0}', '\u{4e0}', SC_Upper),
+ ('\u{4e1}', '\u{4e1}', SC_Lower), ('\u{4e2}', '\u{4e2}', SC_Upper), ('\u{4e3}', '\u{4e3}',
+ SC_Lower), ('\u{4e4}', '\u{4e4}', SC_Upper), ('\u{4e5}', '\u{4e5}', SC_Lower), ('\u{4e6}',
+ '\u{4e6}', SC_Upper), ('\u{4e7}', '\u{4e7}', SC_Lower), ('\u{4e8}', '\u{4e8}', SC_Upper),
+ ('\u{4e9}', '\u{4e9}', SC_Lower), ('\u{4ea}', '\u{4ea}', SC_Upper), ('\u{4eb}', '\u{4eb}',
+ SC_Lower), ('\u{4ec}', '\u{4ec}', SC_Upper), ('\u{4ed}', '\u{4ed}', SC_Lower), ('\u{4ee}',
+ '\u{4ee}', SC_Upper), ('\u{4ef}', '\u{4ef}', SC_Lower), ('\u{4f0}', '\u{4f0}', SC_Upper),
+ ('\u{4f1}', '\u{4f1}', SC_Lower), ('\u{4f2}', '\u{4f2}', SC_Upper), ('\u{4f3}', '\u{4f3}',
+ SC_Lower), ('\u{4f4}', '\u{4f4}', SC_Upper), ('\u{4f5}', '\u{4f5}', SC_Lower), ('\u{4f6}',
+ '\u{4f6}', SC_Upper), ('\u{4f7}', '\u{4f7}', SC_Lower), ('\u{4f8}', '\u{4f8}', SC_Upper),
+ ('\u{4f9}', '\u{4f9}', SC_Lower), ('\u{4fa}', '\u{4fa}', SC_Upper), ('\u{4fb}', '\u{4fb}',
+ SC_Lower), ('\u{4fc}', '\u{4fc}', SC_Upper), ('\u{4fd}', '\u{4fd}', SC_Lower), ('\u{4fe}',
+ '\u{4fe}', SC_Upper), ('\u{4ff}', '\u{4ff}', SC_Lower), ('\u{500}', '\u{500}', SC_Upper),
+ ('\u{501}', '\u{501}', SC_Lower), ('\u{502}', '\u{502}', SC_Upper), ('\u{503}', '\u{503}',
+ SC_Lower), ('\u{504}', '\u{504}', SC_Upper), ('\u{505}', '\u{505}', SC_Lower), ('\u{506}',
+ '\u{506}', SC_Upper), ('\u{507}', '\u{507}', SC_Lower), ('\u{508}', '\u{508}', SC_Upper),
+ ('\u{509}', '\u{509}', SC_Lower), ('\u{50a}', '\u{50a}', SC_Upper), ('\u{50b}', '\u{50b}',
+ SC_Lower), ('\u{50c}', '\u{50c}', SC_Upper), ('\u{50d}', '\u{50d}', SC_Lower), ('\u{50e}',
+ '\u{50e}', SC_Upper), ('\u{50f}', '\u{50f}', SC_Lower), ('\u{510}', '\u{510}', SC_Upper),
+ ('\u{511}', '\u{511}', SC_Lower), ('\u{512}', '\u{512}', SC_Upper), ('\u{513}', '\u{513}',
+ SC_Lower), ('\u{514}', '\u{514}', SC_Upper), ('\u{515}', '\u{515}', SC_Lower), ('\u{516}',
+ '\u{516}', SC_Upper), ('\u{517}', '\u{517}', SC_Lower), ('\u{518}', '\u{518}', SC_Upper),
+ ('\u{519}', '\u{519}', SC_Lower), ('\u{51a}', '\u{51a}', SC_Upper), ('\u{51b}', '\u{51b}',
+ SC_Lower), ('\u{51c}', '\u{51c}', SC_Upper), ('\u{51d}', '\u{51d}', SC_Lower), ('\u{51e}',
+ '\u{51e}', SC_Upper), ('\u{51f}', '\u{51f}', SC_Lower), ('\u{520}', '\u{520}', SC_Upper),
+ ('\u{521}', '\u{521}', SC_Lower), ('\u{522}', '\u{522}', SC_Upper), ('\u{523}', '\u{523}',
+ SC_Lower), ('\u{524}', '\u{524}', SC_Upper), ('\u{525}', '\u{525}', SC_Lower), ('\u{526}',
+ '\u{526}', SC_Upper), ('\u{527}', '\u{527}', SC_Lower), ('\u{528}', '\u{528}', SC_Upper),
+ ('\u{529}', '\u{529}', SC_Lower), ('\u{52a}', '\u{52a}', SC_Upper), ('\u{52b}', '\u{52b}',
+ SC_Lower), ('\u{52c}', '\u{52c}', SC_Upper), ('\u{52d}', '\u{52d}', SC_Lower), ('\u{52e}',
+ '\u{52e}', SC_Upper), ('\u{52f}', '\u{52f}', SC_Lower), ('\u{531}', '\u{556}', SC_Upper),
+ ('\u{559}', '\u{559}', SC_OLetter), ('\u{55d}', '\u{55d}', SC_SContinue), ('\u{560}',
+ '\u{588}', SC_Lower), ('\u{589}', '\u{589}', SC_STerm), ('\u{591}', '\u{5bd}', SC_Extend),
+ ('\u{5bf}', '\u{5bf}', SC_Extend), ('\u{5c1}', '\u{5c2}', SC_Extend), ('\u{5c4}', '\u{5c5}',
+ SC_Extend), ('\u{5c7}', '\u{5c7}', SC_Extend), ('\u{5d0}', '\u{5ea}', SC_OLetter),
+ ('\u{5ef}', '\u{5f3}', SC_OLetter), ('\u{600}', '\u{605}', SC_Format), ('\u{60c}',
+ '\u{60d}', SC_SContinue), ('\u{610}', '\u{61a}', SC_Extend), ('\u{61c}', '\u{61c}',
+ SC_Format), ('\u{61e}', '\u{61f}', SC_STerm), ('\u{620}', '\u{64a}', SC_OLetter),
+ ('\u{64b}', '\u{65f}', SC_Extend), ('\u{660}', '\u{669}', SC_Numeric), ('\u{66b}',
+ '\u{66c}', SC_Numeric), ('\u{66e}', '\u{66f}', SC_OLetter), ('\u{670}', '\u{670}',
+ SC_Extend), ('\u{671}', '\u{6d3}', SC_OLetter), ('\u{6d4}', '\u{6d4}', SC_STerm),
+ ('\u{6d5}', '\u{6d5}', SC_OLetter), ('\u{6d6}', '\u{6dc}', SC_Extend), ('\u{6dd}',
+ '\u{6dd}', SC_Format), ('\u{6df}', '\u{6e4}', SC_Extend), ('\u{6e5}', '\u{6e6}',
+ SC_OLetter), ('\u{6e7}', '\u{6e8}', SC_Extend), ('\u{6ea}', '\u{6ed}', SC_Extend),
+ ('\u{6ee}', '\u{6ef}', SC_OLetter), ('\u{6f0}', '\u{6f9}', SC_Numeric), ('\u{6fa}',
+ '\u{6fc}', SC_OLetter), ('\u{6ff}', '\u{6ff}', SC_OLetter), ('\u{700}', '\u{702}',
+ SC_STerm), ('\u{70f}', '\u{70f}', SC_Format), ('\u{710}', '\u{710}', SC_OLetter),
+ ('\u{711}', '\u{711}', SC_Extend), ('\u{712}', '\u{72f}', SC_OLetter), ('\u{730}',
+ '\u{74a}', SC_Extend), ('\u{74d}', '\u{7a5}', SC_OLetter), ('\u{7a6}', '\u{7b0}',
+ SC_Extend), ('\u{7b1}', '\u{7b1}', SC_OLetter), ('\u{7c0}', '\u{7c9}', SC_Numeric),
+ ('\u{7ca}', '\u{7ea}', SC_OLetter), ('\u{7eb}', '\u{7f3}', SC_Extend), ('\u{7f4}',
+ '\u{7f5}', SC_OLetter), ('\u{7f8}', '\u{7f8}', SC_SContinue), ('\u{7f9}', '\u{7f9}',
+ SC_STerm), ('\u{7fa}', '\u{7fa}', SC_OLetter), ('\u{7fd}', '\u{7fd}', SC_Extend),
+ ('\u{800}', '\u{815}', SC_OLetter), ('\u{816}', '\u{819}', SC_Extend), ('\u{81a}',
+ '\u{81a}', SC_OLetter), ('\u{81b}', '\u{823}', SC_Extend), ('\u{824}', '\u{824}',
+ SC_OLetter), ('\u{825}', '\u{827}', SC_Extend), ('\u{828}', '\u{828}', SC_OLetter),
+ ('\u{829}', '\u{82d}', SC_Extend), ('\u{837}', '\u{837}', SC_STerm), ('\u{839}', '\u{839}',
+ SC_STerm), ('\u{83d}', '\u{83e}', SC_STerm), ('\u{840}', '\u{858}', SC_OLetter), ('\u{859}',
+ '\u{85b}', SC_Extend), ('\u{860}', '\u{86a}', SC_OLetter), ('\u{8a0}', '\u{8b4}',
+ SC_OLetter), ('\u{8b6}', '\u{8bd}', SC_OLetter), ('\u{8d3}', '\u{8e1}', SC_Extend),
+ ('\u{8e2}', '\u{8e2}', SC_Format), ('\u{8e3}', '\u{903}', SC_Extend), ('\u{904}', '\u{939}',
+ SC_OLetter), ('\u{93a}', '\u{93c}', SC_Extend), ('\u{93d}', '\u{93d}', SC_OLetter),
+ ('\u{93e}', '\u{94f}', SC_Extend), ('\u{950}', '\u{950}', SC_OLetter), ('\u{951}',
+ '\u{957}', SC_Extend), ('\u{958}', '\u{961}', SC_OLetter), ('\u{962}', '\u{963}',
+ SC_Extend), ('\u{964}', '\u{965}', SC_STerm), ('\u{966}', '\u{96f}', SC_Numeric),
+ ('\u{971}', '\u{980}', SC_OLetter), ('\u{981}', '\u{983}', SC_Extend), ('\u{985}',
+ '\u{98c}', SC_OLetter), ('\u{98f}', '\u{990}', SC_OLetter), ('\u{993}', '\u{9a8}',
+ SC_OLetter), ('\u{9aa}', '\u{9b0}', SC_OLetter), ('\u{9b2}', '\u{9b2}', SC_OLetter),
+ ('\u{9b6}', '\u{9b9}', SC_OLetter), ('\u{9bc}', '\u{9bc}', SC_Extend), ('\u{9bd}',
+ '\u{9bd}', SC_OLetter), ('\u{9be}', '\u{9c4}', SC_Extend), ('\u{9c7}', '\u{9c8}',
+ SC_Extend), ('\u{9cb}', '\u{9cd}', SC_Extend), ('\u{9ce}', '\u{9ce}', SC_OLetter),
+ ('\u{9d7}', '\u{9d7}', SC_Extend), ('\u{9dc}', '\u{9dd}', SC_OLetter), ('\u{9df}',
+ '\u{9e1}', SC_OLetter), ('\u{9e2}', '\u{9e3}', SC_Extend), ('\u{9e6}', '\u{9ef}',
+ SC_Numeric), ('\u{9f0}', '\u{9f1}', SC_OLetter), ('\u{9fc}', '\u{9fc}', SC_OLetter),
+ ('\u{9fe}', '\u{9fe}', SC_Extend), ('\u{a01}', '\u{a03}', SC_Extend), ('\u{a05}', '\u{a0a}',
+ SC_OLetter), ('\u{a0f}', '\u{a10}', SC_OLetter), ('\u{a13}', '\u{a28}', SC_OLetter),
+ ('\u{a2a}', '\u{a30}', SC_OLetter), ('\u{a32}', '\u{a33}', SC_OLetter), ('\u{a35}',
+ '\u{a36}', SC_OLetter), ('\u{a38}', '\u{a39}', SC_OLetter), ('\u{a3c}', '\u{a3c}',
+ SC_Extend), ('\u{a3e}', '\u{a42}', SC_Extend), ('\u{a47}', '\u{a48}', SC_Extend),
+ ('\u{a4b}', '\u{a4d}', SC_Extend), ('\u{a51}', '\u{a51}', SC_Extend), ('\u{a59}', '\u{a5c}',
+ SC_OLetter), ('\u{a5e}', '\u{a5e}', SC_OLetter), ('\u{a66}', '\u{a6f}', SC_Numeric),
+ ('\u{a70}', '\u{a71}', SC_Extend), ('\u{a72}', '\u{a74}', SC_OLetter), ('\u{a75}',
+ '\u{a75}', SC_Extend), ('\u{a81}', '\u{a83}', SC_Extend), ('\u{a85}', '\u{a8d}',
+ SC_OLetter), ('\u{a8f}', '\u{a91}', SC_OLetter), ('\u{a93}', '\u{aa8}', SC_OLetter),
+ ('\u{aaa}', '\u{ab0}', SC_OLetter), ('\u{ab2}', '\u{ab3}', SC_OLetter), ('\u{ab5}',
+ '\u{ab9}', SC_OLetter), ('\u{abc}', '\u{abc}', SC_Extend), ('\u{abd}', '\u{abd}',
+ SC_OLetter), ('\u{abe}', '\u{ac5}', SC_Extend), ('\u{ac7}', '\u{ac9}', SC_Extend),
+ ('\u{acb}', '\u{acd}', SC_Extend), ('\u{ad0}', '\u{ad0}', SC_OLetter), ('\u{ae0}',
+ '\u{ae1}', SC_OLetter), ('\u{ae2}', '\u{ae3}', SC_Extend), ('\u{ae6}', '\u{aef}',
+ SC_Numeric), ('\u{af9}', '\u{af9}', SC_OLetter), ('\u{afa}', '\u{aff}', SC_Extend),
+ ('\u{b01}', '\u{b03}', SC_Extend), ('\u{b05}', '\u{b0c}', SC_OLetter), ('\u{b0f}',
+ '\u{b10}', SC_OLetter), ('\u{b13}', '\u{b28}', SC_OLetter), ('\u{b2a}', '\u{b30}',
+ SC_OLetter), ('\u{b32}', '\u{b33}', SC_OLetter), ('\u{b35}', '\u{b39}', SC_OLetter),
+ ('\u{b3c}', '\u{b3c}', SC_Extend), ('\u{b3d}', '\u{b3d}', SC_OLetter), ('\u{b3e}',
+ '\u{b44}', SC_Extend), ('\u{b47}', '\u{b48}', SC_Extend), ('\u{b4b}', '\u{b4d}', SC_Extend),
+ ('\u{b56}', '\u{b57}', SC_Extend), ('\u{b5c}', '\u{b5d}', SC_OLetter), ('\u{b5f}',
+ '\u{b61}', SC_OLetter), ('\u{b62}', '\u{b63}', SC_Extend), ('\u{b66}', '\u{b6f}',
+ SC_Numeric), ('\u{b71}', '\u{b71}', SC_OLetter), ('\u{b82}', '\u{b82}', SC_Extend),
+ ('\u{b83}', '\u{b83}', SC_OLetter), ('\u{b85}', '\u{b8a}', SC_OLetter), ('\u{b8e}',
+ '\u{b90}', SC_OLetter), ('\u{b92}', '\u{b95}', SC_OLetter), ('\u{b99}', '\u{b9a}',
+ SC_OLetter), ('\u{b9c}', '\u{b9c}', SC_OLetter), ('\u{b9e}', '\u{b9f}', SC_OLetter),
+ ('\u{ba3}', '\u{ba4}', SC_OLetter), ('\u{ba8}', '\u{baa}', SC_OLetter), ('\u{bae}',
+ '\u{bb9}', SC_OLetter), ('\u{bbe}', '\u{bc2}', SC_Extend), ('\u{bc6}', '\u{bc8}',
+ SC_Extend), ('\u{bca}', '\u{bcd}', SC_Extend), ('\u{bd0}', '\u{bd0}', SC_OLetter),
+ ('\u{bd7}', '\u{bd7}', SC_Extend), ('\u{be6}', '\u{bef}', SC_Numeric), ('\u{c00}',
+ '\u{c04}', SC_Extend), ('\u{c05}', '\u{c0c}', SC_OLetter), ('\u{c0e}', '\u{c10}',
+ SC_OLetter), ('\u{c12}', '\u{c28}', SC_OLetter), ('\u{c2a}', '\u{c39}', SC_OLetter),
+ ('\u{c3d}', '\u{c3d}', SC_OLetter), ('\u{c3e}', '\u{c44}', SC_Extend), ('\u{c46}',
+ '\u{c48}', SC_Extend), ('\u{c4a}', '\u{c4d}', SC_Extend), ('\u{c55}', '\u{c56}', SC_Extend),
+ ('\u{c58}', '\u{c5a}', SC_OLetter), ('\u{c60}', '\u{c61}', SC_OLetter), ('\u{c62}',
+ '\u{c63}', SC_Extend), ('\u{c66}', '\u{c6f}', SC_Numeric), ('\u{c80}', '\u{c80}',
+ SC_OLetter), ('\u{c81}', '\u{c83}', SC_Extend), ('\u{c85}', '\u{c8c}', SC_OLetter),
+ ('\u{c8e}', '\u{c90}', SC_OLetter), ('\u{c92}', '\u{ca8}', SC_OLetter), ('\u{caa}',
+ '\u{cb3}', SC_OLetter), ('\u{cb5}', '\u{cb9}', SC_OLetter), ('\u{cbc}', '\u{cbc}',
+ SC_Extend), ('\u{cbd}', '\u{cbd}', SC_OLetter), ('\u{cbe}', '\u{cc4}', SC_Extend),
+ ('\u{cc6}', '\u{cc8}', SC_Extend), ('\u{cca}', '\u{ccd}', SC_Extend), ('\u{cd5}', '\u{cd6}',
+ SC_Extend), ('\u{cde}', '\u{cde}', SC_OLetter), ('\u{ce0}', '\u{ce1}', SC_OLetter),
+ ('\u{ce2}', '\u{ce3}', SC_Extend), ('\u{ce6}', '\u{cef}', SC_Numeric), ('\u{cf1}',
+ '\u{cf2}', SC_OLetter), ('\u{d00}', '\u{d03}', SC_Extend), ('\u{d05}', '\u{d0c}',
+ SC_OLetter), ('\u{d0e}', '\u{d10}', SC_OLetter), ('\u{d12}', '\u{d3a}', SC_OLetter),
+ ('\u{d3b}', '\u{d3c}', SC_Extend), ('\u{d3d}', '\u{d3d}', SC_OLetter), ('\u{d3e}',
+ '\u{d44}', SC_Extend), ('\u{d46}', '\u{d48}', SC_Extend), ('\u{d4a}', '\u{d4d}', SC_Extend),
+ ('\u{d4e}', '\u{d4e}', SC_OLetter), ('\u{d54}', '\u{d56}', SC_OLetter), ('\u{d57}',
+ '\u{d57}', SC_Extend), ('\u{d5f}', '\u{d61}', SC_OLetter), ('\u{d62}', '\u{d63}',
+ SC_Extend), ('\u{d66}', '\u{d6f}', SC_Numeric), ('\u{d7a}', '\u{d7f}', SC_OLetter),
+ ('\u{d82}', '\u{d83}', SC_Extend), ('\u{d85}', '\u{d96}', SC_OLetter), ('\u{d9a}',
+ '\u{db1}', SC_OLetter), ('\u{db3}', '\u{dbb}', SC_OLetter), ('\u{dbd}', '\u{dbd}',
+ SC_OLetter), ('\u{dc0}', '\u{dc6}', SC_OLetter), ('\u{dca}', '\u{dca}', SC_Extend),
+ ('\u{dcf}', '\u{dd4}', SC_Extend), ('\u{dd6}', '\u{dd6}', SC_Extend), ('\u{dd8}', '\u{ddf}',
+ SC_Extend), ('\u{de6}', '\u{def}', SC_Numeric), ('\u{df2}', '\u{df3}', SC_Extend),
+ ('\u{e01}', '\u{e30}', SC_OLetter), ('\u{e31}', '\u{e31}', SC_Extend), ('\u{e32}',
+ '\u{e33}', SC_OLetter), ('\u{e34}', '\u{e3a}', SC_Extend), ('\u{e40}', '\u{e46}',
+ SC_OLetter), ('\u{e47}', '\u{e4e}', SC_Extend), ('\u{e50}', '\u{e59}', SC_Numeric),
+ ('\u{e81}', '\u{e82}', SC_OLetter), ('\u{e84}', '\u{e84}', SC_OLetter), ('\u{e86}',
+ '\u{e8a}', SC_OLetter), ('\u{e8c}', '\u{ea3}', SC_OLetter), ('\u{ea5}', '\u{ea5}',
+ SC_OLetter), ('\u{ea7}', '\u{eb0}', SC_OLetter), ('\u{eb1}', '\u{eb1}', SC_Extend),
+ ('\u{eb2}', '\u{eb3}', SC_OLetter), ('\u{eb4}', '\u{ebc}', SC_Extend), ('\u{ebd}',
+ '\u{ebd}', SC_OLetter), ('\u{ec0}', '\u{ec4}', SC_OLetter), ('\u{ec6}', '\u{ec6}',
+ SC_OLetter), ('\u{ec8}', '\u{ecd}', SC_Extend), ('\u{ed0}', '\u{ed9}', SC_Numeric),
+ ('\u{edc}', '\u{edf}', SC_OLetter), ('\u{f00}', '\u{f00}', SC_OLetter), ('\u{f18}',
+ '\u{f19}', SC_Extend), ('\u{f20}', '\u{f29}', SC_Numeric), ('\u{f35}', '\u{f35}',
+ SC_Extend), ('\u{f37}', '\u{f37}', SC_Extend), ('\u{f39}', '\u{f39}', SC_Extend),
+ ('\u{f3a}', '\u{f3d}', SC_Close), ('\u{f3e}', '\u{f3f}', SC_Extend), ('\u{f40}', '\u{f47}',
+ SC_OLetter), ('\u{f49}', '\u{f6c}', SC_OLetter), ('\u{f71}', '\u{f84}', SC_Extend),
+ ('\u{f86}', '\u{f87}', SC_Extend), ('\u{f88}', '\u{f8c}', SC_OLetter), ('\u{f8d}',
+ '\u{f97}', SC_Extend), ('\u{f99}', '\u{fbc}', SC_Extend), ('\u{fc6}', '\u{fc6}', SC_Extend),
+ ('\u{1000}', '\u{102a}', SC_OLetter), ('\u{102b}', '\u{103e}', SC_Extend), ('\u{103f}',
+ '\u{103f}', SC_OLetter), ('\u{1040}', '\u{1049}', SC_Numeric), ('\u{104a}', '\u{104b}',
+ SC_STerm), ('\u{1050}', '\u{1055}', SC_OLetter), ('\u{1056}', '\u{1059}', SC_Extend),
+ ('\u{105a}', '\u{105d}', SC_OLetter), ('\u{105e}', '\u{1060}', SC_Extend), ('\u{1061}',
+ '\u{1061}', SC_OLetter), ('\u{1062}', '\u{1064}', SC_Extend), ('\u{1065}', '\u{1066}',
+ SC_OLetter), ('\u{1067}', '\u{106d}', SC_Extend), ('\u{106e}', '\u{1070}', SC_OLetter),
+ ('\u{1071}', '\u{1074}', SC_Extend), ('\u{1075}', '\u{1081}', SC_OLetter), ('\u{1082}',
+ '\u{108d}', SC_Extend), ('\u{108e}', '\u{108e}', SC_OLetter), ('\u{108f}', '\u{108f}',
+ SC_Extend), ('\u{1090}', '\u{1099}', SC_Numeric), ('\u{109a}', '\u{109d}', SC_Extend),
+ ('\u{10a0}', '\u{10c5}', SC_Upper), ('\u{10c7}', '\u{10c7}', SC_Upper), ('\u{10cd}',
+ '\u{10cd}', SC_Upper), ('\u{10d0}', '\u{10fa}', SC_OLetter), ('\u{10fc}', '\u{1248}',
+ SC_OLetter), ('\u{124a}', '\u{124d}', SC_OLetter), ('\u{1250}', '\u{1256}', SC_OLetter),
+ ('\u{1258}', '\u{1258}', SC_OLetter), ('\u{125a}', '\u{125d}', SC_OLetter), ('\u{1260}',
+ '\u{1288}', SC_OLetter), ('\u{128a}', '\u{128d}', SC_OLetter), ('\u{1290}', '\u{12b0}',
+ SC_OLetter), ('\u{12b2}', '\u{12b5}', SC_OLetter), ('\u{12b8}', '\u{12be}', SC_OLetter),
+ ('\u{12c0}', '\u{12c0}', SC_OLetter), ('\u{12c2}', '\u{12c5}', SC_OLetter), ('\u{12c8}',
+ '\u{12d6}', SC_OLetter), ('\u{12d8}', '\u{1310}', SC_OLetter), ('\u{1312}', '\u{1315}',
+ SC_OLetter), ('\u{1318}', '\u{135a}', SC_OLetter), ('\u{135d}', '\u{135f}', SC_Extend),
+ ('\u{1362}', '\u{1362}', SC_STerm), ('\u{1367}', '\u{1368}', SC_STerm), ('\u{1380}',
+ '\u{138f}', SC_OLetter), ('\u{13a0}', '\u{13f5}', SC_Upper), ('\u{13f8}', '\u{13fd}',
+ SC_Lower), ('\u{1401}', '\u{166c}', SC_OLetter), ('\u{166e}', '\u{166e}', SC_STerm),
+ ('\u{166f}', '\u{167f}', SC_OLetter), ('\u{1680}', '\u{1680}', SC_Sp), ('\u{1681}',
+ '\u{169a}', SC_OLetter), ('\u{169b}', '\u{169c}', SC_Close), ('\u{16a0}', '\u{16ea}',
+ SC_OLetter), ('\u{16ee}', '\u{16f8}', SC_OLetter), ('\u{1700}', '\u{170c}', SC_OLetter),
+ ('\u{170e}', '\u{1711}', SC_OLetter), ('\u{1712}', '\u{1714}', SC_Extend), ('\u{1720}',
+ '\u{1731}', SC_OLetter), ('\u{1732}', '\u{1734}', SC_Extend), ('\u{1735}', '\u{1736}',
+ SC_STerm), ('\u{1740}', '\u{1751}', SC_OLetter), ('\u{1752}', '\u{1753}', SC_Extend),
+ ('\u{1760}', '\u{176c}', SC_OLetter), ('\u{176e}', '\u{1770}', SC_OLetter), ('\u{1772}',
+ '\u{1773}', SC_Extend), ('\u{1780}', '\u{17b3}', SC_OLetter), ('\u{17b4}', '\u{17d3}',
+ SC_Extend), ('\u{17d7}', '\u{17d7}', SC_OLetter), ('\u{17dc}', '\u{17dc}', SC_OLetter),
+ ('\u{17dd}', '\u{17dd}', SC_Extend), ('\u{17e0}', '\u{17e9}', SC_Numeric), ('\u{1802}',
+ '\u{1802}', SC_SContinue), ('\u{1803}', '\u{1803}', SC_STerm), ('\u{1808}', '\u{1808}',
+ SC_SContinue), ('\u{1809}', '\u{1809}', SC_STerm), ('\u{180b}', '\u{180d}', SC_Extend),
+ ('\u{180e}', '\u{180e}', SC_Format), ('\u{1810}', '\u{1819}', SC_Numeric), ('\u{1820}',
+ '\u{1878}', SC_OLetter), ('\u{1880}', '\u{1884}', SC_OLetter), ('\u{1885}', '\u{1886}',
+ SC_Extend), ('\u{1887}', '\u{18a8}', SC_OLetter), ('\u{18a9}', '\u{18a9}', SC_Extend),
+ ('\u{18aa}', '\u{18aa}', SC_OLetter), ('\u{18b0}', '\u{18f5}', SC_OLetter), ('\u{1900}',
+ '\u{191e}', SC_OLetter), ('\u{1920}', '\u{192b}', SC_Extend), ('\u{1930}', '\u{193b}',
+ SC_Extend), ('\u{1944}', '\u{1945}', SC_STerm), ('\u{1946}', '\u{194f}', SC_Numeric),
+ ('\u{1950}', '\u{196d}', SC_OLetter), ('\u{1970}', '\u{1974}', SC_OLetter), ('\u{1980}',
+ '\u{19ab}', SC_OLetter), ('\u{19b0}', '\u{19c9}', SC_OLetter), ('\u{19d0}', '\u{19d9}',
+ SC_Numeric), ('\u{1a00}', '\u{1a16}', SC_OLetter), ('\u{1a17}', '\u{1a1b}', SC_Extend),
+ ('\u{1a20}', '\u{1a54}', SC_OLetter), ('\u{1a55}', '\u{1a5e}', SC_Extend), ('\u{1a60}',
+ '\u{1a7c}', SC_Extend), ('\u{1a7f}', '\u{1a7f}', SC_Extend), ('\u{1a80}', '\u{1a89}',
+ SC_Numeric), ('\u{1a90}', '\u{1a99}', SC_Numeric), ('\u{1aa7}', '\u{1aa7}', SC_OLetter),
+ ('\u{1aa8}', '\u{1aab}', SC_STerm), ('\u{1ab0}', '\u{1abe}', SC_Extend), ('\u{1b00}',
+ '\u{1b04}', SC_Extend), ('\u{1b05}', '\u{1b33}', SC_OLetter), ('\u{1b34}', '\u{1b44}',
+ SC_Extend), ('\u{1b45}', '\u{1b4b}', SC_OLetter), ('\u{1b50}', '\u{1b59}', SC_Numeric),
+ ('\u{1b5a}', '\u{1b5b}', SC_STerm), ('\u{1b5e}', '\u{1b5f}', SC_STerm), ('\u{1b6b}',
+ '\u{1b73}', SC_Extend), ('\u{1b80}', '\u{1b82}', SC_Extend), ('\u{1b83}', '\u{1ba0}',
+ SC_OLetter), ('\u{1ba1}', '\u{1bad}', SC_Extend), ('\u{1bae}', '\u{1baf}', SC_OLetter),
+ ('\u{1bb0}', '\u{1bb9}', SC_Numeric), ('\u{1bba}', '\u{1be5}', SC_OLetter), ('\u{1be6}',
+ '\u{1bf3}', SC_Extend), ('\u{1c00}', '\u{1c23}', SC_OLetter), ('\u{1c24}', '\u{1c37}',
+ SC_Extend), ('\u{1c3b}', '\u{1c3c}', SC_STerm), ('\u{1c40}', '\u{1c49}', SC_Numeric),
+ ('\u{1c4d}', '\u{1c4f}', SC_OLetter), ('\u{1c50}', '\u{1c59}', SC_Numeric), ('\u{1c5a}',
+ '\u{1c7d}', SC_OLetter), ('\u{1c7e}', '\u{1c7f}', SC_STerm), ('\u{1c80}', '\u{1c88}',
+ SC_Lower), ('\u{1c90}', '\u{1cba}', SC_OLetter), ('\u{1cbd}', '\u{1cbf}', SC_OLetter),
+ ('\u{1cd0}', '\u{1cd2}', SC_Extend), ('\u{1cd4}', '\u{1ce8}', SC_Extend), ('\u{1ce9}',
+ '\u{1cec}', SC_OLetter), ('\u{1ced}', '\u{1ced}', SC_Extend), ('\u{1cee}', '\u{1cf3}',
+ SC_OLetter), ('\u{1cf4}', '\u{1cf4}', SC_Extend), ('\u{1cf5}', '\u{1cf6}', SC_OLetter),
+ ('\u{1cf7}', '\u{1cf9}', SC_Extend), ('\u{1cfa}', '\u{1cfa}', SC_OLetter), ('\u{1d00}',
+ '\u{1dbf}', SC_Lower), ('\u{1dc0}', '\u{1df9}', SC_Extend), ('\u{1dfb}', '\u{1dff}',
+ SC_Extend), ('\u{1e00}', '\u{1e00}', SC_Upper), ('\u{1e01}', '\u{1e01}', SC_Lower),
+ ('\u{1e02}', '\u{1e02}', SC_Upper), ('\u{1e03}', '\u{1e03}', SC_Lower), ('\u{1e04}',
+ '\u{1e04}', SC_Upper), ('\u{1e05}', '\u{1e05}', SC_Lower), ('\u{1e06}', '\u{1e06}',
+ SC_Upper), ('\u{1e07}', '\u{1e07}', SC_Lower), ('\u{1e08}', '\u{1e08}', SC_Upper),
+ ('\u{1e09}', '\u{1e09}', SC_Lower), ('\u{1e0a}', '\u{1e0a}', SC_Upper), ('\u{1e0b}',
+ '\u{1e0b}', SC_Lower), ('\u{1e0c}', '\u{1e0c}', SC_Upper), ('\u{1e0d}', '\u{1e0d}',
+ SC_Lower), ('\u{1e0e}', '\u{1e0e}', SC_Upper), ('\u{1e0f}', '\u{1e0f}', SC_Lower),
+ ('\u{1e10}', '\u{1e10}', SC_Upper), ('\u{1e11}', '\u{1e11}', SC_Lower), ('\u{1e12}',
+ '\u{1e12}', SC_Upper), ('\u{1e13}', '\u{1e13}', SC_Lower), ('\u{1e14}', '\u{1e14}',
+ SC_Upper), ('\u{1e15}', '\u{1e15}', SC_Lower), ('\u{1e16}', '\u{1e16}', SC_Upper),
+ ('\u{1e17}', '\u{1e17}', SC_Lower), ('\u{1e18}', '\u{1e18}', SC_Upper), ('\u{1e19}',
+ '\u{1e19}', SC_Lower), ('\u{1e1a}', '\u{1e1a}', SC_Upper), ('\u{1e1b}', '\u{1e1b}',
+ SC_Lower), ('\u{1e1c}', '\u{1e1c}', SC_Upper), ('\u{1e1d}', '\u{1e1d}', SC_Lower),
+ ('\u{1e1e}', '\u{1e1e}', SC_Upper), ('\u{1e1f}', '\u{1e1f}', SC_Lower), ('\u{1e20}',
+ '\u{1e20}', SC_Upper), ('\u{1e21}', '\u{1e21}', SC_Lower), ('\u{1e22}', '\u{1e22}',
+ SC_Upper), ('\u{1e23}', '\u{1e23}', SC_Lower), ('\u{1e24}', '\u{1e24}', SC_Upper),
+ ('\u{1e25}', '\u{1e25}', SC_Lower), ('\u{1e26}', '\u{1e26}', SC_Upper), ('\u{1e27}',
+ '\u{1e27}', SC_Lower), ('\u{1e28}', '\u{1e28}', SC_Upper), ('\u{1e29}', '\u{1e29}',
+ SC_Lower), ('\u{1e2a}', '\u{1e2a}', SC_Upper), ('\u{1e2b}', '\u{1e2b}', SC_Lower),
+ ('\u{1e2c}', '\u{1e2c}', SC_Upper), ('\u{1e2d}', '\u{1e2d}', SC_Lower), ('\u{1e2e}',
+ '\u{1e2e}', SC_Upper), ('\u{1e2f}', '\u{1e2f}', SC_Lower), ('\u{1e30}', '\u{1e30}',
+ SC_Upper), ('\u{1e31}', '\u{1e31}', SC_Lower), ('\u{1e32}', '\u{1e32}', SC_Upper),
+ ('\u{1e33}', '\u{1e33}', SC_Lower), ('\u{1e34}', '\u{1e34}', SC_Upper), ('\u{1e35}',
+ '\u{1e35}', SC_Lower), ('\u{1e36}', '\u{1e36}', SC_Upper), ('\u{1e37}', '\u{1e37}',
+ SC_Lower), ('\u{1e38}', '\u{1e38}', SC_Upper), ('\u{1e39}', '\u{1e39}', SC_Lower),
+ ('\u{1e3a}', '\u{1e3a}', SC_Upper), ('\u{1e3b}', '\u{1e3b}', SC_Lower), ('\u{1e3c}',
+ '\u{1e3c}', SC_Upper), ('\u{1e3d}', '\u{1e3d}', SC_Lower), ('\u{1e3e}', '\u{1e3e}',
+ SC_Upper), ('\u{1e3f}', '\u{1e3f}', SC_Lower), ('\u{1e40}', '\u{1e40}', SC_Upper),
+ ('\u{1e41}', '\u{1e41}', SC_Lower), ('\u{1e42}', '\u{1e42}', SC_Upper), ('\u{1e43}',
+ '\u{1e43}', SC_Lower), ('\u{1e44}', '\u{1e44}', SC_Upper), ('\u{1e45}', '\u{1e45}',
+ SC_Lower), ('\u{1e46}', '\u{1e46}', SC_Upper), ('\u{1e47}', '\u{1e47}', SC_Lower),
+ ('\u{1e48}', '\u{1e48}', SC_Upper), ('\u{1e49}', '\u{1e49}', SC_Lower), ('\u{1e4a}',
+ '\u{1e4a}', SC_Upper), ('\u{1e4b}', '\u{1e4b}', SC_Lower), ('\u{1e4c}', '\u{1e4c}',
+ SC_Upper), ('\u{1e4d}', '\u{1e4d}', SC_Lower), ('\u{1e4e}', '\u{1e4e}', SC_Upper),
+ ('\u{1e4f}', '\u{1e4f}', SC_Lower), ('\u{1e50}', '\u{1e50}', SC_Upper), ('\u{1e51}',
+ '\u{1e51}', SC_Lower), ('\u{1e52}', '\u{1e52}', SC_Upper), ('\u{1e53}', '\u{1e53}',
+ SC_Lower), ('\u{1e54}', '\u{1e54}', SC_Upper), ('\u{1e55}', '\u{1e55}', SC_Lower),
+ ('\u{1e56}', '\u{1e56}', SC_Upper), ('\u{1e57}', '\u{1e57}', SC_Lower), ('\u{1e58}',
+ '\u{1e58}', SC_Upper), ('\u{1e59}', '\u{1e59}', SC_Lower), ('\u{1e5a}', '\u{1e5a}',
+ SC_Upper), ('\u{1e5b}', '\u{1e5b}', SC_Lower), ('\u{1e5c}', '\u{1e5c}', SC_Upper),
+ ('\u{1e5d}', '\u{1e5d}', SC_Lower), ('\u{1e5e}', '\u{1e5e}', SC_Upper), ('\u{1e5f}',
+ '\u{1e5f}', SC_Lower), ('\u{1e60}', '\u{1e60}', SC_Upper), ('\u{1e61}', '\u{1e61}',
+ SC_Lower), ('\u{1e62}', '\u{1e62}', SC_Upper), ('\u{1e63}', '\u{1e63}', SC_Lower),
+ ('\u{1e64}', '\u{1e64}', SC_Upper), ('\u{1e65}', '\u{1e65}', SC_Lower), ('\u{1e66}',
+ '\u{1e66}', SC_Upper), ('\u{1e67}', '\u{1e67}', SC_Lower), ('\u{1e68}', '\u{1e68}',
+ SC_Upper), ('\u{1e69}', '\u{1e69}', SC_Lower), ('\u{1e6a}', '\u{1e6a}', SC_Upper),
+ ('\u{1e6b}', '\u{1e6b}', SC_Lower), ('\u{1e6c}', '\u{1e6c}', SC_Upper), ('\u{1e6d}',
+ '\u{1e6d}', SC_Lower), ('\u{1e6e}', '\u{1e6e}', SC_Upper), ('\u{1e6f}', '\u{1e6f}',
+ SC_Lower), ('\u{1e70}', '\u{1e70}', SC_Upper), ('\u{1e71}', '\u{1e71}', SC_Lower),
+ ('\u{1e72}', '\u{1e72}', SC_Upper), ('\u{1e73}', '\u{1e73}', SC_Lower), ('\u{1e74}',
+ '\u{1e74}', SC_Upper), ('\u{1e75}', '\u{1e75}', SC_Lower), ('\u{1e76}', '\u{1e76}',
+ SC_Upper), ('\u{1e77}', '\u{1e77}', SC_Lower), ('\u{1e78}', '\u{1e78}', SC_Upper),
+ ('\u{1e79}', '\u{1e79}', SC_Lower), ('\u{1e7a}', '\u{1e7a}', SC_Upper), ('\u{1e7b}',
+ '\u{1e7b}', SC_Lower), ('\u{1e7c}', '\u{1e7c}', SC_Upper), ('\u{1e7d}', '\u{1e7d}',
+ SC_Lower), ('\u{1e7e}', '\u{1e7e}', SC_Upper), ('\u{1e7f}', '\u{1e7f}', SC_Lower),
+ ('\u{1e80}', '\u{1e80}', SC_Upper), ('\u{1e81}', '\u{1e81}', SC_Lower), ('\u{1e82}',
+ '\u{1e82}', SC_Upper), ('\u{1e83}', '\u{1e83}', SC_Lower), ('\u{1e84}', '\u{1e84}',
+ SC_Upper), ('\u{1e85}', '\u{1e85}', SC_Lower), ('\u{1e86}', '\u{1e86}', SC_Upper),
+ ('\u{1e87}', '\u{1e87}', SC_Lower), ('\u{1e88}', '\u{1e88}', SC_Upper), ('\u{1e89}',
+ '\u{1e89}', SC_Lower), ('\u{1e8a}', '\u{1e8a}', SC_Upper), ('\u{1e8b}', '\u{1e8b}',
+ SC_Lower), ('\u{1e8c}', '\u{1e8c}', SC_Upper), ('\u{1e8d}', '\u{1e8d}', SC_Lower),
+ ('\u{1e8e}', '\u{1e8e}', SC_Upper), ('\u{1e8f}', '\u{1e8f}', SC_Lower), ('\u{1e90}',
+ '\u{1e90}', SC_Upper), ('\u{1e91}', '\u{1e91}', SC_Lower), ('\u{1e92}', '\u{1e92}',
+ SC_Upper), ('\u{1e93}', '\u{1e93}', SC_Lower), ('\u{1e94}', '\u{1e94}', SC_Upper),
+ ('\u{1e95}', '\u{1e9d}', SC_Lower), ('\u{1e9e}', '\u{1e9e}', SC_Upper), ('\u{1e9f}',
+ '\u{1e9f}', SC_Lower), ('\u{1ea0}', '\u{1ea0}', SC_Upper), ('\u{1ea1}', '\u{1ea1}',
+ SC_Lower), ('\u{1ea2}', '\u{1ea2}', SC_Upper), ('\u{1ea3}', '\u{1ea3}', SC_Lower),
+ ('\u{1ea4}', '\u{1ea4}', SC_Upper), ('\u{1ea5}', '\u{1ea5}', SC_Lower), ('\u{1ea6}',
+ '\u{1ea6}', SC_Upper), ('\u{1ea7}', '\u{1ea7}', SC_Lower), ('\u{1ea8}', '\u{1ea8}',
+ SC_Upper), ('\u{1ea9}', '\u{1ea9}', SC_Lower), ('\u{1eaa}', '\u{1eaa}', SC_Upper),
+ ('\u{1eab}', '\u{1eab}', SC_Lower), ('\u{1eac}', '\u{1eac}', SC_Upper), ('\u{1ead}',
+ '\u{1ead}', SC_Lower), ('\u{1eae}', '\u{1eae}', SC_Upper), ('\u{1eaf}', '\u{1eaf}',
+ SC_Lower), ('\u{1eb0}', '\u{1eb0}', SC_Upper), ('\u{1eb1}', '\u{1eb1}', SC_Lower),
+ ('\u{1eb2}', '\u{1eb2}', SC_Upper), ('\u{1eb3}', '\u{1eb3}', SC_Lower), ('\u{1eb4}',
+ '\u{1eb4}', SC_Upper), ('\u{1eb5}', '\u{1eb5}', SC_Lower), ('\u{1eb6}', '\u{1eb6}',
+ SC_Upper), ('\u{1eb7}', '\u{1eb7}', SC_Lower), ('\u{1eb8}', '\u{1eb8}', SC_Upper),
+ ('\u{1eb9}', '\u{1eb9}', SC_Lower), ('\u{1eba}', '\u{1eba}', SC_Upper), ('\u{1ebb}',
+ '\u{1ebb}', SC_Lower), ('\u{1ebc}', '\u{1ebc}', SC_Upper), ('\u{1ebd}', '\u{1ebd}',
+ SC_Lower), ('\u{1ebe}', '\u{1ebe}', SC_Upper), ('\u{1ebf}', '\u{1ebf}', SC_Lower),
+ ('\u{1ec0}', '\u{1ec0}', SC_Upper), ('\u{1ec1}', '\u{1ec1}', SC_Lower), ('\u{1ec2}',
+ '\u{1ec2}', SC_Upper), ('\u{1ec3}', '\u{1ec3}', SC_Lower), ('\u{1ec4}', '\u{1ec4}',
+ SC_Upper), ('\u{1ec5}', '\u{1ec5}', SC_Lower), ('\u{1ec6}', '\u{1ec6}', SC_Upper),
+ ('\u{1ec7}', '\u{1ec7}', SC_Lower), ('\u{1ec8}', '\u{1ec8}', SC_Upper), ('\u{1ec9}',
+ '\u{1ec9}', SC_Lower), ('\u{1eca}', '\u{1eca}', SC_Upper), ('\u{1ecb}', '\u{1ecb}',
+ SC_Lower), ('\u{1ecc}', '\u{1ecc}', SC_Upper), ('\u{1ecd}', '\u{1ecd}', SC_Lower),
+ ('\u{1ece}', '\u{1ece}', SC_Upper), ('\u{1ecf}', '\u{1ecf}', SC_Lower), ('\u{1ed0}',
+ '\u{1ed0}', SC_Upper), ('\u{1ed1}', '\u{1ed1}', SC_Lower), ('\u{1ed2}', '\u{1ed2}',
+ SC_Upper), ('\u{1ed3}', '\u{1ed3}', SC_Lower), ('\u{1ed4}', '\u{1ed4}', SC_Upper),
+ ('\u{1ed5}', '\u{1ed5}', SC_Lower), ('\u{1ed6}', '\u{1ed6}', SC_Upper), ('\u{1ed7}',
+ '\u{1ed7}', SC_Lower), ('\u{1ed8}', '\u{1ed8}', SC_Upper), ('\u{1ed9}', '\u{1ed9}',
+ SC_Lower), ('\u{1eda}', '\u{1eda}', SC_Upper), ('\u{1edb}', '\u{1edb}', SC_Lower),
+ ('\u{1edc}', '\u{1edc}', SC_Upper), ('\u{1edd}', '\u{1edd}', SC_Lower), ('\u{1ede}',
+ '\u{1ede}', SC_Upper), ('\u{1edf}', '\u{1edf}', SC_Lower), ('\u{1ee0}', '\u{1ee0}',
+ SC_Upper), ('\u{1ee1}', '\u{1ee1}', SC_Lower), ('\u{1ee2}', '\u{1ee2}', SC_Upper),
+ ('\u{1ee3}', '\u{1ee3}', SC_Lower), ('\u{1ee4}', '\u{1ee4}', SC_Upper), ('\u{1ee5}',
+ '\u{1ee5}', SC_Lower), ('\u{1ee6}', '\u{1ee6}', SC_Upper), ('\u{1ee7}', '\u{1ee7}',
+ SC_Lower), ('\u{1ee8}', '\u{1ee8}', SC_Upper), ('\u{1ee9}', '\u{1ee9}', SC_Lower),
+ ('\u{1eea}', '\u{1eea}', SC_Upper), ('\u{1eeb}', '\u{1eeb}', SC_Lower), ('\u{1eec}',
+ '\u{1eec}', SC_Upper), ('\u{1eed}', '\u{1eed}', SC_Lower), ('\u{1eee}', '\u{1eee}',
+ SC_Upper), ('\u{1eef}', '\u{1eef}', SC_Lower), ('\u{1ef0}', '\u{1ef0}', SC_Upper),
+ ('\u{1ef1}', '\u{1ef1}', SC_Lower), ('\u{1ef2}', '\u{1ef2}', SC_Upper), ('\u{1ef3}',
+ '\u{1ef3}', SC_Lower), ('\u{1ef4}', '\u{1ef4}', SC_Upper), ('\u{1ef5}', '\u{1ef5}',
+ SC_Lower), ('\u{1ef6}', '\u{1ef6}', SC_Upper), ('\u{1ef7}', '\u{1ef7}', SC_Lower),
+ ('\u{1ef8}', '\u{1ef8}', SC_Upper), ('\u{1ef9}', '\u{1ef9}', SC_Lower), ('\u{1efa}',
+ '\u{1efa}', SC_Upper), ('\u{1efb}', '\u{1efb}', SC_Lower), ('\u{1efc}', '\u{1efc}',
+ SC_Upper), ('\u{1efd}', '\u{1efd}', SC_Lower), ('\u{1efe}', '\u{1efe}', SC_Upper),
+ ('\u{1eff}', '\u{1f07}', SC_Lower), ('\u{1f08}', '\u{1f0f}', SC_Upper), ('\u{1f10}',
+ '\u{1f15}', SC_Lower), ('\u{1f18}', '\u{1f1d}', SC_Upper), ('\u{1f20}', '\u{1f27}',
+ SC_Lower), ('\u{1f28}', '\u{1f2f}', SC_Upper), ('\u{1f30}', '\u{1f37}', SC_Lower),
+ ('\u{1f38}', '\u{1f3f}', SC_Upper), ('\u{1f40}', '\u{1f45}', SC_Lower), ('\u{1f48}',
+ '\u{1f4d}', SC_Upper), ('\u{1f50}', '\u{1f57}', SC_Lower), ('\u{1f59}', '\u{1f59}',
+ SC_Upper), ('\u{1f5b}', '\u{1f5b}', SC_Upper), ('\u{1f5d}', '\u{1f5d}', SC_Upper),
+ ('\u{1f5f}', '\u{1f5f}', SC_Upper), ('\u{1f60}', '\u{1f67}', SC_Lower), ('\u{1f68}',
+ '\u{1f6f}', SC_Upper), ('\u{1f70}', '\u{1f7d}', SC_Lower), ('\u{1f80}', '\u{1f87}',
+ SC_Lower), ('\u{1f88}', '\u{1f8f}', SC_Upper), ('\u{1f90}', '\u{1f97}', SC_Lower),
+ ('\u{1f98}', '\u{1f9f}', SC_Upper), ('\u{1fa0}', '\u{1fa7}', SC_Lower), ('\u{1fa8}',
+ '\u{1faf}', SC_Upper), ('\u{1fb0}', '\u{1fb4}', SC_Lower), ('\u{1fb6}', '\u{1fb7}',
+ SC_Lower), ('\u{1fb8}', '\u{1fbc}', SC_Upper), ('\u{1fbe}', '\u{1fbe}', SC_Lower),
+ ('\u{1fc2}', '\u{1fc4}', SC_Lower), ('\u{1fc6}', '\u{1fc7}', SC_Lower), ('\u{1fc8}',
+ '\u{1fcc}', SC_Upper), ('\u{1fd0}', '\u{1fd3}', SC_Lower), ('\u{1fd6}', '\u{1fd7}',
+ SC_Lower), ('\u{1fd8}', '\u{1fdb}', SC_Upper), ('\u{1fe0}', '\u{1fe7}', SC_Lower),
+ ('\u{1fe8}', '\u{1fec}', SC_Upper), ('\u{1ff2}', '\u{1ff4}', SC_Lower), ('\u{1ff6}',
+ '\u{1ff7}', SC_Lower), ('\u{1ff8}', '\u{1ffc}', SC_Upper), ('\u{2000}', '\u{200a}', SC_Sp),
+ ('\u{200b}', '\u{200b}', SC_Format), ('\u{200c}', '\u{200d}', SC_Extend), ('\u{200e}',
+ '\u{200f}', SC_Format), ('\u{2013}', '\u{2014}', SC_SContinue), ('\u{2018}', '\u{201f}',
+ SC_Close), ('\u{2024}', '\u{2024}', SC_ATerm), ('\u{2028}', '\u{2029}', SC_Sep),
+ ('\u{202a}', '\u{202e}', SC_Format), ('\u{202f}', '\u{202f}', SC_Sp), ('\u{2039}',
+ '\u{203a}', SC_Close), ('\u{203c}', '\u{203d}', SC_STerm), ('\u{2045}', '\u{2046}',
+ SC_Close), ('\u{2047}', '\u{2049}', SC_STerm), ('\u{205f}', '\u{205f}', SC_Sp), ('\u{2060}',
+ '\u{2064}', SC_Format), ('\u{2066}', '\u{206f}', SC_Format), ('\u{2071}', '\u{2071}',
+ SC_Lower), ('\u{207d}', '\u{207e}', SC_Close), ('\u{207f}', '\u{207f}', SC_Lower),
+ ('\u{208d}', '\u{208e}', SC_Close), ('\u{2090}', '\u{209c}', SC_Lower), ('\u{20d0}',
+ '\u{20f0}', SC_Extend), ('\u{2102}', '\u{2102}', SC_Upper), ('\u{2107}', '\u{2107}',
+ SC_Upper), ('\u{210a}', '\u{210a}', SC_Lower), ('\u{210b}', '\u{210d}', SC_Upper),
+ ('\u{210e}', '\u{210f}', SC_Lower), ('\u{2110}', '\u{2112}', SC_Upper), ('\u{2113}',
+ '\u{2113}', SC_Lower), ('\u{2115}', '\u{2115}', SC_Upper), ('\u{2119}', '\u{211d}',
+ SC_Upper), ('\u{2124}', '\u{2124}', SC_Upper), ('\u{2126}', '\u{2126}', SC_Upper),
+ ('\u{2128}', '\u{2128}', SC_Upper), ('\u{212a}', '\u{212d}', SC_Upper), ('\u{212f}',
+ '\u{212f}', SC_Lower), ('\u{2130}', '\u{2133}', SC_Upper), ('\u{2134}', '\u{2134}',
+ SC_Lower), ('\u{2135}', '\u{2138}', SC_OLetter), ('\u{2139}', '\u{2139}', SC_Lower),
+ ('\u{213c}', '\u{213d}', SC_Lower), ('\u{213e}', '\u{213f}', SC_Upper), ('\u{2145}',
+ '\u{2145}', SC_Upper), ('\u{2146}', '\u{2149}', SC_Lower), ('\u{214e}', '\u{214e}',
+ SC_Lower), ('\u{2160}', '\u{216f}', SC_Upper), ('\u{2170}', '\u{217f}', SC_Lower),
+ ('\u{2180}', '\u{2182}', SC_OLetter), ('\u{2183}', '\u{2183}', SC_Upper), ('\u{2184}',
+ '\u{2184}', SC_Lower), ('\u{2185}', '\u{2188}', SC_OLetter), ('\u{2308}', '\u{230b}',
+ SC_Close), ('\u{2329}', '\u{232a}', SC_Close), ('\u{24b6}', '\u{24cf}', SC_Upper),
+ ('\u{24d0}', '\u{24e9}', SC_Lower), ('\u{275b}', '\u{2760}', SC_Close), ('\u{2768}',
+ '\u{2775}', SC_Close), ('\u{27c5}', '\u{27c6}', SC_Close), ('\u{27e6}', '\u{27ef}',
+ SC_Close), ('\u{2983}', '\u{2998}', SC_Close), ('\u{29d8}', '\u{29db}', SC_Close),
+ ('\u{29fc}', '\u{29fd}', SC_Close), ('\u{2c00}', '\u{2c2e}', SC_Upper), ('\u{2c30}',
+ '\u{2c5e}', SC_Lower), ('\u{2c60}', '\u{2c60}', SC_Upper), ('\u{2c61}', '\u{2c61}',
+ SC_Lower), ('\u{2c62}', '\u{2c64}', SC_Upper), ('\u{2c65}', '\u{2c66}', SC_Lower),
+ ('\u{2c67}', '\u{2c67}', SC_Upper), ('\u{2c68}', '\u{2c68}', SC_Lower), ('\u{2c69}',
+ '\u{2c69}', SC_Upper), ('\u{2c6a}', '\u{2c6a}', SC_Lower), ('\u{2c6b}', '\u{2c6b}',
+ SC_Upper), ('\u{2c6c}', '\u{2c6c}', SC_Lower), ('\u{2c6d}', '\u{2c70}', SC_Upper),
+ ('\u{2c71}', '\u{2c71}', SC_Lower), ('\u{2c72}', '\u{2c72}', SC_Upper), ('\u{2c73}',
+ '\u{2c74}', SC_Lower), ('\u{2c75}', '\u{2c75}', SC_Upper), ('\u{2c76}', '\u{2c7d}',
+ SC_Lower), ('\u{2c7e}', '\u{2c80}', SC_Upper), ('\u{2c81}', '\u{2c81}', SC_Lower),
+ ('\u{2c82}', '\u{2c82}', SC_Upper), ('\u{2c83}', '\u{2c83}', SC_Lower), ('\u{2c84}',
+ '\u{2c84}', SC_Upper), ('\u{2c85}', '\u{2c85}', SC_Lower), ('\u{2c86}', '\u{2c86}',
+ SC_Upper), ('\u{2c87}', '\u{2c87}', SC_Lower), ('\u{2c88}', '\u{2c88}', SC_Upper),
+ ('\u{2c89}', '\u{2c89}', SC_Lower), ('\u{2c8a}', '\u{2c8a}', SC_Upper), ('\u{2c8b}',
+ '\u{2c8b}', SC_Lower), ('\u{2c8c}', '\u{2c8c}', SC_Upper), ('\u{2c8d}', '\u{2c8d}',
+ SC_Lower), ('\u{2c8e}', '\u{2c8e}', SC_Upper), ('\u{2c8f}', '\u{2c8f}', SC_Lower),
+ ('\u{2c90}', '\u{2c90}', SC_Upper), ('\u{2c91}', '\u{2c91}', SC_Lower), ('\u{2c92}',
+ '\u{2c92}', SC_Upper), ('\u{2c93}', '\u{2c93}', SC_Lower), ('\u{2c94}', '\u{2c94}',
+ SC_Upper), ('\u{2c95}', '\u{2c95}', SC_Lower), ('\u{2c96}', '\u{2c96}', SC_Upper),
+ ('\u{2c97}', '\u{2c97}', SC_Lower), ('\u{2c98}', '\u{2c98}', SC_Upper), ('\u{2c99}',
+ '\u{2c99}', SC_Lower), ('\u{2c9a}', '\u{2c9a}', SC_Upper), ('\u{2c9b}', '\u{2c9b}',
+ SC_Lower), ('\u{2c9c}', '\u{2c9c}', SC_Upper), ('\u{2c9d}', '\u{2c9d}', SC_Lower),
+ ('\u{2c9e}', '\u{2c9e}', SC_Upper), ('\u{2c9f}', '\u{2c9f}', SC_Lower), ('\u{2ca0}',
+ '\u{2ca0}', SC_Upper), ('\u{2ca1}', '\u{2ca1}', SC_Lower), ('\u{2ca2}', '\u{2ca2}',
+ SC_Upper), ('\u{2ca3}', '\u{2ca3}', SC_Lower), ('\u{2ca4}', '\u{2ca4}', SC_Upper),
+ ('\u{2ca5}', '\u{2ca5}', SC_Lower), ('\u{2ca6}', '\u{2ca6}', SC_Upper), ('\u{2ca7}',
+ '\u{2ca7}', SC_Lower), ('\u{2ca8}', '\u{2ca8}', SC_Upper), ('\u{2ca9}', '\u{2ca9}',
+ SC_Lower), ('\u{2caa}', '\u{2caa}', SC_Upper), ('\u{2cab}', '\u{2cab}', SC_Lower),
+ ('\u{2cac}', '\u{2cac}', SC_Upper), ('\u{2cad}', '\u{2cad}', SC_Lower), ('\u{2cae}',
+ '\u{2cae}', SC_Upper), ('\u{2caf}', '\u{2caf}', SC_Lower), ('\u{2cb0}', '\u{2cb0}',
+ SC_Upper), ('\u{2cb1}', '\u{2cb1}', SC_Lower), ('\u{2cb2}', '\u{2cb2}', SC_Upper),
+ ('\u{2cb3}', '\u{2cb3}', SC_Lower), ('\u{2cb4}', '\u{2cb4}', SC_Upper), ('\u{2cb5}',
+ '\u{2cb5}', SC_Lower), ('\u{2cb6}', '\u{2cb6}', SC_Upper), ('\u{2cb7}', '\u{2cb7}',
+ SC_Lower), ('\u{2cb8}', '\u{2cb8}', SC_Upper), ('\u{2cb9}', '\u{2cb9}', SC_Lower),
+ ('\u{2cba}', '\u{2cba}', SC_Upper), ('\u{2cbb}', '\u{2cbb}', SC_Lower), ('\u{2cbc}',
+ '\u{2cbc}', SC_Upper), ('\u{2cbd}', '\u{2cbd}', SC_Lower), ('\u{2cbe}', '\u{2cbe}',
+ SC_Upper), ('\u{2cbf}', '\u{2cbf}', SC_Lower), ('\u{2cc0}', '\u{2cc0}', SC_Upper),
+ ('\u{2cc1}', '\u{2cc1}', SC_Lower), ('\u{2cc2}', '\u{2cc2}', SC_Upper), ('\u{2cc3}',
+ '\u{2cc3}', SC_Lower), ('\u{2cc4}', '\u{2cc4}', SC_Upper), ('\u{2cc5}', '\u{2cc5}',
+ SC_Lower), ('\u{2cc6}', '\u{2cc6}', SC_Upper), ('\u{2cc7}', '\u{2cc7}', SC_Lower),
+ ('\u{2cc8}', '\u{2cc8}', SC_Upper), ('\u{2cc9}', '\u{2cc9}', SC_Lower), ('\u{2cca}',
+ '\u{2cca}', SC_Upper), ('\u{2ccb}', '\u{2ccb}', SC_Lower), ('\u{2ccc}', '\u{2ccc}',
+ SC_Upper), ('\u{2ccd}', '\u{2ccd}', SC_Lower), ('\u{2cce}', '\u{2cce}', SC_Upper),
+ ('\u{2ccf}', '\u{2ccf}', SC_Lower), ('\u{2cd0}', '\u{2cd0}', SC_Upper), ('\u{2cd1}',
+ '\u{2cd1}', SC_Lower), ('\u{2cd2}', '\u{2cd2}', SC_Upper), ('\u{2cd3}', '\u{2cd3}',
+ SC_Lower), ('\u{2cd4}', '\u{2cd4}', SC_Upper), ('\u{2cd5}', '\u{2cd5}', SC_Lower),
+ ('\u{2cd6}', '\u{2cd6}', SC_Upper), ('\u{2cd7}', '\u{2cd7}', SC_Lower), ('\u{2cd8}',
+ '\u{2cd8}', SC_Upper), ('\u{2cd9}', '\u{2cd9}', SC_Lower), ('\u{2cda}', '\u{2cda}',
+ SC_Upper), ('\u{2cdb}', '\u{2cdb}', SC_Lower), ('\u{2cdc}', '\u{2cdc}', SC_Upper),
+ ('\u{2cdd}', '\u{2cdd}', SC_Lower), ('\u{2cde}', '\u{2cde}', SC_Upper), ('\u{2cdf}',
+ '\u{2cdf}', SC_Lower), ('\u{2ce0}', '\u{2ce0}', SC_Upper), ('\u{2ce1}', '\u{2ce1}',
+ SC_Lower), ('\u{2ce2}', '\u{2ce2}', SC_Upper), ('\u{2ce3}', '\u{2ce4}', SC_Lower),
+ ('\u{2ceb}', '\u{2ceb}', SC_Upper), ('\u{2cec}', '\u{2cec}', SC_Lower), ('\u{2ced}',
+ '\u{2ced}', SC_Upper), ('\u{2cee}', '\u{2cee}', SC_Lower), ('\u{2cef}', '\u{2cf1}',
+ SC_Extend), ('\u{2cf2}', '\u{2cf2}', SC_Upper), ('\u{2cf3}', '\u{2cf3}', SC_Lower),
+ ('\u{2d00}', '\u{2d25}', SC_Lower), ('\u{2d27}', '\u{2d27}', SC_Lower), ('\u{2d2d}',
+ '\u{2d2d}', SC_Lower), ('\u{2d30}', '\u{2d67}', SC_OLetter), ('\u{2d6f}', '\u{2d6f}',
+ SC_OLetter), ('\u{2d7f}', '\u{2d7f}', SC_Extend), ('\u{2d80}', '\u{2d96}', SC_OLetter),
+ ('\u{2da0}', '\u{2da6}', SC_OLetter), ('\u{2da8}', '\u{2dae}', SC_OLetter), ('\u{2db0}',
+ '\u{2db6}', SC_OLetter), ('\u{2db8}', '\u{2dbe}', SC_OLetter), ('\u{2dc0}', '\u{2dc6}',
+ SC_OLetter), ('\u{2dc8}', '\u{2dce}', SC_OLetter), ('\u{2dd0}', '\u{2dd6}', SC_OLetter),
+ ('\u{2dd8}', '\u{2dde}', SC_OLetter), ('\u{2de0}', '\u{2dff}', SC_Extend), ('\u{2e00}',
+ '\u{2e0d}', SC_Close), ('\u{2e1c}', '\u{2e1d}', SC_Close), ('\u{2e20}', '\u{2e29}',
+ SC_Close), ('\u{2e2e}', '\u{2e2e}', SC_STerm), ('\u{2e2f}', '\u{2e2f}', SC_OLetter),
+ ('\u{2e3c}', '\u{2e3c}', SC_STerm), ('\u{2e42}', '\u{2e42}', SC_Close), ('\u{3000}',
+ '\u{3000}', SC_Sp), ('\u{3001}', '\u{3001}', SC_SContinue), ('\u{3002}', '\u{3002}',
+ SC_STerm), ('\u{3005}', '\u{3007}', SC_OLetter), ('\u{3008}', '\u{3011}', SC_Close),
+ ('\u{3014}', '\u{301b}', SC_Close), ('\u{301d}', '\u{301f}', SC_Close), ('\u{3021}',
+ '\u{3029}', SC_OLetter), ('\u{302a}', '\u{302f}', SC_Extend), ('\u{3031}', '\u{3035}',
+ SC_OLetter), ('\u{3038}', '\u{303c}', SC_OLetter), ('\u{3041}', '\u{3096}', SC_OLetter),
+ ('\u{3099}', '\u{309a}', SC_Extend), ('\u{309d}', '\u{309f}', SC_OLetter), ('\u{30a1}',
+ '\u{30fa}', SC_OLetter), ('\u{30fc}', '\u{30ff}', SC_OLetter), ('\u{3105}', '\u{312f}',
+ SC_OLetter), ('\u{3131}', '\u{318e}', SC_OLetter), ('\u{31a0}', '\u{31ba}', SC_OLetter),
+ ('\u{31f0}', '\u{31ff}', SC_OLetter), ('\u{3400}', '\u{4db5}', SC_OLetter), ('\u{4e00}',
+ '\u{9fef}', SC_OLetter), ('\u{a000}', '\u{a48c}', SC_OLetter), ('\u{a4d0}', '\u{a4fd}',
+ SC_OLetter), ('\u{a4ff}', '\u{a4ff}', SC_STerm), ('\u{a500}', '\u{a60c}', SC_OLetter),
+ ('\u{a60e}', '\u{a60f}', SC_STerm), ('\u{a610}', '\u{a61f}', SC_OLetter), ('\u{a620}',
+ '\u{a629}', SC_Numeric), ('\u{a62a}', '\u{a62b}', SC_OLetter), ('\u{a640}', '\u{a640}',
+ SC_Upper), ('\u{a641}', '\u{a641}', SC_Lower), ('\u{a642}', '\u{a642}', SC_Upper),
+ ('\u{a643}', '\u{a643}', SC_Lower), ('\u{a644}', '\u{a644}', SC_Upper), ('\u{a645}',
+ '\u{a645}', SC_Lower), ('\u{a646}', '\u{a646}', SC_Upper), ('\u{a647}', '\u{a647}',
+ SC_Lower), ('\u{a648}', '\u{a648}', SC_Upper), ('\u{a649}', '\u{a649}', SC_Lower),
+ ('\u{a64a}', '\u{a64a}', SC_Upper), ('\u{a64b}', '\u{a64b}', SC_Lower), ('\u{a64c}',
+ '\u{a64c}', SC_Upper), ('\u{a64d}', '\u{a64d}', SC_Lower), ('\u{a64e}', '\u{a64e}',
+ SC_Upper), ('\u{a64f}', '\u{a64f}', SC_Lower), ('\u{a650}', '\u{a650}', SC_Upper),
+ ('\u{a651}', '\u{a651}', SC_Lower), ('\u{a652}', '\u{a652}', SC_Upper), ('\u{a653}',
+ '\u{a653}', SC_Lower), ('\u{a654}', '\u{a654}', SC_Upper), ('\u{a655}', '\u{a655}',
+ SC_Lower), ('\u{a656}', '\u{a656}', SC_Upper), ('\u{a657}', '\u{a657}', SC_Lower),
+ ('\u{a658}', '\u{a658}', SC_Upper), ('\u{a659}', '\u{a659}', SC_Lower), ('\u{a65a}',
+ '\u{a65a}', SC_Upper), ('\u{a65b}', '\u{a65b}', SC_Lower), ('\u{a65c}', '\u{a65c}',
+ SC_Upper), ('\u{a65d}', '\u{a65d}', SC_Lower), ('\u{a65e}', '\u{a65e}', SC_Upper),
+ ('\u{a65f}', '\u{a65f}', SC_Lower), ('\u{a660}', '\u{a660}', SC_Upper), ('\u{a661}',
+ '\u{a661}', SC_Lower), ('\u{a662}', '\u{a662}', SC_Upper), ('\u{a663}', '\u{a663}',
+ SC_Lower), ('\u{a664}', '\u{a664}', SC_Upper), ('\u{a665}', '\u{a665}', SC_Lower),
+ ('\u{a666}', '\u{a666}', SC_Upper), ('\u{a667}', '\u{a667}', SC_Lower), ('\u{a668}',
+ '\u{a668}', SC_Upper), ('\u{a669}', '\u{a669}', SC_Lower), ('\u{a66a}', '\u{a66a}',
+ SC_Upper), ('\u{a66b}', '\u{a66b}', SC_Lower), ('\u{a66c}', '\u{a66c}', SC_Upper),
+ ('\u{a66d}', '\u{a66d}', SC_Lower), ('\u{a66e}', '\u{a66e}', SC_OLetter), ('\u{a66f}',
+ '\u{a672}', SC_Extend), ('\u{a674}', '\u{a67d}', SC_Extend), ('\u{a67f}', '\u{a67f}',
+ SC_OLetter), ('\u{a680}', '\u{a680}', SC_Upper), ('\u{a681}', '\u{a681}', SC_Lower),
+ ('\u{a682}', '\u{a682}', SC_Upper), ('\u{a683}', '\u{a683}', SC_Lower), ('\u{a684}',
+ '\u{a684}', SC_Upper), ('\u{a685}', '\u{a685}', SC_Lower), ('\u{a686}', '\u{a686}',
+ SC_Upper), ('\u{a687}', '\u{a687}', SC_Lower), ('\u{a688}', '\u{a688}', SC_Upper),
+ ('\u{a689}', '\u{a689}', SC_Lower), ('\u{a68a}', '\u{a68a}', SC_Upper), ('\u{a68b}',
+ '\u{a68b}', SC_Lower), ('\u{a68c}', '\u{a68c}', SC_Upper), ('\u{a68d}', '\u{a68d}',
+ SC_Lower), ('\u{a68e}', '\u{a68e}', SC_Upper), ('\u{a68f}', '\u{a68f}', SC_Lower),
+ ('\u{a690}', '\u{a690}', SC_Upper), ('\u{a691}', '\u{a691}', SC_Lower), ('\u{a692}',
+ '\u{a692}', SC_Upper), ('\u{a693}', '\u{a693}', SC_Lower), ('\u{a694}', '\u{a694}',
+ SC_Upper), ('\u{a695}', '\u{a695}', SC_Lower), ('\u{a696}', '\u{a696}', SC_Upper),
+ ('\u{a697}', '\u{a697}', SC_Lower), ('\u{a698}', '\u{a698}', SC_Upper), ('\u{a699}',
+ '\u{a699}', SC_Lower), ('\u{a69a}', '\u{a69a}', SC_Upper), ('\u{a69b}', '\u{a69d}',
+ SC_Lower), ('\u{a69e}', '\u{a69f}', SC_Extend), ('\u{a6a0}', '\u{a6ef}', SC_OLetter),
+ ('\u{a6f0}', '\u{a6f1}', SC_Extend), ('\u{a6f3}', '\u{a6f3}', SC_STerm), ('\u{a6f7}',
+ '\u{a6f7}', SC_STerm), ('\u{a717}', '\u{a71f}', SC_OLetter), ('\u{a722}', '\u{a722}',
+ SC_Upper), ('\u{a723}', '\u{a723}', SC_Lower), ('\u{a724}', '\u{a724}', SC_Upper),
+ ('\u{a725}', '\u{a725}', SC_Lower), ('\u{a726}', '\u{a726}', SC_Upper), ('\u{a727}',
+ '\u{a727}', SC_Lower), ('\u{a728}', '\u{a728}', SC_Upper), ('\u{a729}', '\u{a729}',
+ SC_Lower), ('\u{a72a}', '\u{a72a}', SC_Upper), ('\u{a72b}', '\u{a72b}', SC_Lower),
+ ('\u{a72c}', '\u{a72c}', SC_Upper), ('\u{a72d}', '\u{a72d}', SC_Lower), ('\u{a72e}',
+ '\u{a72e}', SC_Upper), ('\u{a72f}', '\u{a731}', SC_Lower), ('\u{a732}', '\u{a732}',
+ SC_Upper), ('\u{a733}', '\u{a733}', SC_Lower), ('\u{a734}', '\u{a734}', SC_Upper),
+ ('\u{a735}', '\u{a735}', SC_Lower), ('\u{a736}', '\u{a736}', SC_Upper), ('\u{a737}',
+ '\u{a737}', SC_Lower), ('\u{a738}', '\u{a738}', SC_Upper), ('\u{a739}', '\u{a739}',
+ SC_Lower), ('\u{a73a}', '\u{a73a}', SC_Upper), ('\u{a73b}', '\u{a73b}', SC_Lower),
+ ('\u{a73c}', '\u{a73c}', SC_Upper), ('\u{a73d}', '\u{a73d}', SC_Lower), ('\u{a73e}',
+ '\u{a73e}', SC_Upper), ('\u{a73f}', '\u{a73f}', SC_Lower), ('\u{a740}', '\u{a740}',
+ SC_Upper), ('\u{a741}', '\u{a741}', SC_Lower), ('\u{a742}', '\u{a742}', SC_Upper),
+ ('\u{a743}', '\u{a743}', SC_Lower), ('\u{a744}', '\u{a744}', SC_Upper), ('\u{a745}',
+ '\u{a745}', SC_Lower), ('\u{a746}', '\u{a746}', SC_Upper), ('\u{a747}', '\u{a747}',
+ SC_Lower), ('\u{a748}', '\u{a748}', SC_Upper), ('\u{a749}', '\u{a749}', SC_Lower),
+ ('\u{a74a}', '\u{a74a}', SC_Upper), ('\u{a74b}', '\u{a74b}', SC_Lower), ('\u{a74c}',
+ '\u{a74c}', SC_Upper), ('\u{a74d}', '\u{a74d}', SC_Lower), ('\u{a74e}', '\u{a74e}',
+ SC_Upper), ('\u{a74f}', '\u{a74f}', SC_Lower), ('\u{a750}', '\u{a750}', SC_Upper),
+ ('\u{a751}', '\u{a751}', SC_Lower), ('\u{a752}', '\u{a752}', SC_Upper), ('\u{a753}',
+ '\u{a753}', SC_Lower), ('\u{a754}', '\u{a754}', SC_Upper), ('\u{a755}', '\u{a755}',
+ SC_Lower), ('\u{a756}', '\u{a756}', SC_Upper), ('\u{a757}', '\u{a757}', SC_Lower),
+ ('\u{a758}', '\u{a758}', SC_Upper), ('\u{a759}', '\u{a759}', SC_Lower), ('\u{a75a}',
+ '\u{a75a}', SC_Upper), ('\u{a75b}', '\u{a75b}', SC_Lower), ('\u{a75c}', '\u{a75c}',
+ SC_Upper), ('\u{a75d}', '\u{a75d}', SC_Lower), ('\u{a75e}', '\u{a75e}', SC_Upper),
+ ('\u{a75f}', '\u{a75f}', SC_Lower), ('\u{a760}', '\u{a760}', SC_Upper), ('\u{a761}',
+ '\u{a761}', SC_Lower), ('\u{a762}', '\u{a762}', SC_Upper), ('\u{a763}', '\u{a763}',
+ SC_Lower), ('\u{a764}', '\u{a764}', SC_Upper), ('\u{a765}', '\u{a765}', SC_Lower),
+ ('\u{a766}', '\u{a766}', SC_Upper), ('\u{a767}', '\u{a767}', SC_Lower), ('\u{a768}',
+ '\u{a768}', SC_Upper), ('\u{a769}', '\u{a769}', SC_Lower), ('\u{a76a}', '\u{a76a}',
+ SC_Upper), ('\u{a76b}', '\u{a76b}', SC_Lower), ('\u{a76c}', '\u{a76c}', SC_Upper),
+ ('\u{a76d}', '\u{a76d}', SC_Lower), ('\u{a76e}', '\u{a76e}', SC_Upper), ('\u{a76f}',
+ '\u{a778}', SC_Lower), ('\u{a779}', '\u{a779}', SC_Upper), ('\u{a77a}', '\u{a77a}',
+ SC_Lower), ('\u{a77b}', '\u{a77b}', SC_Upper), ('\u{a77c}', '\u{a77c}', SC_Lower),
+ ('\u{a77d}', '\u{a77e}', SC_Upper), ('\u{a77f}', '\u{a77f}', SC_Lower), ('\u{a780}',
+ '\u{a780}', SC_Upper), ('\u{a781}', '\u{a781}', SC_Lower), ('\u{a782}', '\u{a782}',
+ SC_Upper), ('\u{a783}', '\u{a783}', SC_Lower), ('\u{a784}', '\u{a784}', SC_Upper),
+ ('\u{a785}', '\u{a785}', SC_Lower), ('\u{a786}', '\u{a786}', SC_Upper), ('\u{a787}',
+ '\u{a787}', SC_Lower), ('\u{a788}', '\u{a788}', SC_OLetter), ('\u{a78b}', '\u{a78b}',
+ SC_Upper), ('\u{a78c}', '\u{a78c}', SC_Lower), ('\u{a78d}', '\u{a78d}', SC_Upper),
+ ('\u{a78e}', '\u{a78e}', SC_Lower), ('\u{a78f}', '\u{a78f}', SC_OLetter), ('\u{a790}',
+ '\u{a790}', SC_Upper), ('\u{a791}', '\u{a791}', SC_Lower), ('\u{a792}', '\u{a792}',
+ SC_Upper), ('\u{a793}', '\u{a795}', SC_Lower), ('\u{a796}', '\u{a796}', SC_Upper),
+ ('\u{a797}', '\u{a797}', SC_Lower), ('\u{a798}', '\u{a798}', SC_Upper), ('\u{a799}',
+ '\u{a799}', SC_Lower), ('\u{a79a}', '\u{a79a}', SC_Upper), ('\u{a79b}', '\u{a79b}',
+ SC_Lower), ('\u{a79c}', '\u{a79c}', SC_Upper), ('\u{a79d}', '\u{a79d}', SC_Lower),
+ ('\u{a79e}', '\u{a79e}', SC_Upper), ('\u{a79f}', '\u{a79f}', SC_Lower), ('\u{a7a0}',
+ '\u{a7a0}', SC_Upper), ('\u{a7a1}', '\u{a7a1}', SC_Lower), ('\u{a7a2}', '\u{a7a2}',
+ SC_Upper), ('\u{a7a3}', '\u{a7a3}', SC_Lower), ('\u{a7a4}', '\u{a7a4}', SC_Upper),
+ ('\u{a7a5}', '\u{a7a5}', SC_Lower), ('\u{a7a6}', '\u{a7a6}', SC_Upper), ('\u{a7a7}',
+ '\u{a7a7}', SC_Lower), ('\u{a7a8}', '\u{a7a8}', SC_Upper), ('\u{a7a9}', '\u{a7a9}',
+ SC_Lower), ('\u{a7aa}', '\u{a7ae}', SC_Upper), ('\u{a7af}', '\u{a7af}', SC_Lower),
+ ('\u{a7b0}', '\u{a7b4}', SC_Upper), ('\u{a7b5}', '\u{a7b5}', SC_Lower), ('\u{a7b6}',
+ '\u{a7b6}', SC_Upper), ('\u{a7b7}', '\u{a7b7}', SC_Lower), ('\u{a7b8}', '\u{a7b8}',
+ SC_Upper), ('\u{a7b9}', '\u{a7b9}', SC_Lower), ('\u{a7ba}', '\u{a7ba}', SC_Upper),
+ ('\u{a7bb}', '\u{a7bb}', SC_Lower), ('\u{a7bc}', '\u{a7bc}', SC_Upper), ('\u{a7bd}',
+ '\u{a7bd}', SC_Lower), ('\u{a7be}', '\u{a7be}', SC_Upper), ('\u{a7bf}', '\u{a7bf}',
+ SC_Lower), ('\u{a7c2}', '\u{a7c2}', SC_Upper), ('\u{a7c3}', '\u{a7c3}', SC_Lower),
+ ('\u{a7c4}', '\u{a7c6}', SC_Upper), ('\u{a7f7}', '\u{a7f7}', SC_OLetter), ('\u{a7f8}',
+ '\u{a7fa}', SC_Lower), ('\u{a7fb}', '\u{a801}', SC_OLetter), ('\u{a802}', '\u{a802}',
+ SC_Extend), ('\u{a803}', '\u{a805}', SC_OLetter), ('\u{a806}', '\u{a806}', SC_Extend),
+ ('\u{a807}', '\u{a80a}', SC_OLetter), ('\u{a80b}', '\u{a80b}', SC_Extend), ('\u{a80c}',
+ '\u{a822}', SC_OLetter), ('\u{a823}', '\u{a827}', SC_Extend), ('\u{a840}', '\u{a873}',
+ SC_OLetter), ('\u{a876}', '\u{a877}', SC_STerm), ('\u{a880}', '\u{a881}', SC_Extend),
+ ('\u{a882}', '\u{a8b3}', SC_OLetter), ('\u{a8b4}', '\u{a8c5}', SC_Extend), ('\u{a8ce}',
+ '\u{a8cf}', SC_STerm), ('\u{a8d0}', '\u{a8d9}', SC_Numeric), ('\u{a8e0}', '\u{a8f1}',
+ SC_Extend), ('\u{a8f2}', '\u{a8f7}', SC_OLetter), ('\u{a8fb}', '\u{a8fb}', SC_OLetter),
+ ('\u{a8fd}', '\u{a8fe}', SC_OLetter), ('\u{a8ff}', '\u{a8ff}', SC_Extend), ('\u{a900}',
+ '\u{a909}', SC_Numeric), ('\u{a90a}', '\u{a925}', SC_OLetter), ('\u{a926}', '\u{a92d}',
+ SC_Extend), ('\u{a92f}', '\u{a92f}', SC_STerm), ('\u{a930}', '\u{a946}', SC_OLetter),
+ ('\u{a947}', '\u{a953}', SC_Extend), ('\u{a960}', '\u{a97c}', SC_OLetter), ('\u{a980}',
+ '\u{a983}', SC_Extend), ('\u{a984}', '\u{a9b2}', SC_OLetter), ('\u{a9b3}', '\u{a9c0}',
+ SC_Extend), ('\u{a9c8}', '\u{a9c9}', SC_STerm), ('\u{a9cf}', '\u{a9cf}', SC_OLetter),
+ ('\u{a9d0}', '\u{a9d9}', SC_Numeric), ('\u{a9e0}', '\u{a9e4}', SC_OLetter), ('\u{a9e5}',
+ '\u{a9e5}', SC_Extend), ('\u{a9e6}', '\u{a9ef}', SC_OLetter), ('\u{a9f0}', '\u{a9f9}',
+ SC_Numeric), ('\u{a9fa}', '\u{a9fe}', SC_OLetter), ('\u{aa00}', '\u{aa28}', SC_OLetter),
+ ('\u{aa29}', '\u{aa36}', SC_Extend), ('\u{aa40}', '\u{aa42}', SC_OLetter), ('\u{aa43}',
+ '\u{aa43}', SC_Extend), ('\u{aa44}', '\u{aa4b}', SC_OLetter), ('\u{aa4c}', '\u{aa4d}',
+ SC_Extend), ('\u{aa50}', '\u{aa59}', SC_Numeric), ('\u{aa5d}', '\u{aa5f}', SC_STerm),
+ ('\u{aa60}', '\u{aa76}', SC_OLetter), ('\u{aa7a}', '\u{aa7a}', SC_OLetter), ('\u{aa7b}',
+ '\u{aa7d}', SC_Extend), ('\u{aa7e}', '\u{aaaf}', SC_OLetter), ('\u{aab0}', '\u{aab0}',
+ SC_Extend), ('\u{aab1}', '\u{aab1}', SC_OLetter), ('\u{aab2}', '\u{aab4}', SC_Extend),
+ ('\u{aab5}', '\u{aab6}', SC_OLetter), ('\u{aab7}', '\u{aab8}', SC_Extend), ('\u{aab9}',
+ '\u{aabd}', SC_OLetter), ('\u{aabe}', '\u{aabf}', SC_Extend), ('\u{aac0}', '\u{aac0}',
+ SC_OLetter), ('\u{aac1}', '\u{aac1}', SC_Extend), ('\u{aac2}', '\u{aac2}', SC_OLetter),
+ ('\u{aadb}', '\u{aadd}', SC_OLetter), ('\u{aae0}', '\u{aaea}', SC_OLetter), ('\u{aaeb}',
+ '\u{aaef}', SC_Extend), ('\u{aaf0}', '\u{aaf1}', SC_STerm), ('\u{aaf2}', '\u{aaf4}',
+ SC_OLetter), ('\u{aaf5}', '\u{aaf6}', SC_Extend), ('\u{ab01}', '\u{ab06}', SC_OLetter),
+ ('\u{ab09}', '\u{ab0e}', SC_OLetter), ('\u{ab11}', '\u{ab16}', SC_OLetter), ('\u{ab20}',
+ '\u{ab26}', SC_OLetter), ('\u{ab28}', '\u{ab2e}', SC_OLetter), ('\u{ab30}', '\u{ab5a}',
+ SC_Lower), ('\u{ab5c}', '\u{ab67}', SC_Lower), ('\u{ab70}', '\u{abbf}', SC_Lower),
+ ('\u{abc0}', '\u{abe2}', SC_OLetter), ('\u{abe3}', '\u{abea}', SC_Extend), ('\u{abeb}',
+ '\u{abeb}', SC_STerm), ('\u{abec}', '\u{abed}', SC_Extend), ('\u{abf0}', '\u{abf9}',
+ SC_Numeric), ('\u{ac00}', '\u{d7a3}', SC_OLetter), ('\u{d7b0}', '\u{d7c6}', SC_OLetter),
+ ('\u{d7cb}', '\u{d7fb}', SC_OLetter), ('\u{f900}', '\u{fa6d}', SC_OLetter), ('\u{fa70}',
+ '\u{fad9}', SC_OLetter), ('\u{fb00}', '\u{fb06}', SC_Lower), ('\u{fb13}', '\u{fb17}',
+ SC_Lower), ('\u{fb1d}', '\u{fb1d}', SC_OLetter), ('\u{fb1e}', '\u{fb1e}', SC_Extend),
+ ('\u{fb1f}', '\u{fb28}', SC_OLetter), ('\u{fb2a}', '\u{fb36}', SC_OLetter), ('\u{fb38}',
+ '\u{fb3c}', SC_OLetter), ('\u{fb3e}', '\u{fb3e}', SC_OLetter), ('\u{fb40}', '\u{fb41}',
+ SC_OLetter), ('\u{fb43}', '\u{fb44}', SC_OLetter), ('\u{fb46}', '\u{fbb1}', SC_OLetter),
+ ('\u{fbd3}', '\u{fd3d}', SC_OLetter), ('\u{fd3e}', '\u{fd3f}', SC_Close), ('\u{fd50}',
+ '\u{fd8f}', SC_OLetter), ('\u{fd92}', '\u{fdc7}', SC_OLetter), ('\u{fdf0}', '\u{fdfb}',
+ SC_OLetter), ('\u{fe00}', '\u{fe0f}', SC_Extend), ('\u{fe10}', '\u{fe11}', SC_SContinue),
+ ('\u{fe13}', '\u{fe13}', SC_SContinue), ('\u{fe17}', '\u{fe18}', SC_Close), ('\u{fe20}',
+ '\u{fe2f}', SC_Extend), ('\u{fe31}', '\u{fe32}', SC_SContinue), ('\u{fe35}', '\u{fe44}',
+ SC_Close), ('\u{fe47}', '\u{fe48}', SC_Close), ('\u{fe50}', '\u{fe51}', SC_SContinue),
+ ('\u{fe52}', '\u{fe52}', SC_ATerm), ('\u{fe55}', '\u{fe55}', SC_SContinue), ('\u{fe56}',
+ '\u{fe57}', SC_STerm), ('\u{fe58}', '\u{fe58}', SC_SContinue), ('\u{fe59}', '\u{fe5e}',
+ SC_Close), ('\u{fe63}', '\u{fe63}', SC_SContinue), ('\u{fe70}', '\u{fe74}', SC_OLetter),
+ ('\u{fe76}', '\u{fefc}', SC_OLetter), ('\u{feff}', '\u{feff}', SC_Format), ('\u{ff01}',
+ '\u{ff01}', SC_STerm), ('\u{ff08}', '\u{ff09}', SC_Close), ('\u{ff0c}', '\u{ff0d}',
+ SC_SContinue), ('\u{ff0e}', '\u{ff0e}', SC_ATerm), ('\u{ff10}', '\u{ff19}', SC_Numeric),
+ ('\u{ff1a}', '\u{ff1a}', SC_SContinue), ('\u{ff1f}', '\u{ff1f}', SC_STerm), ('\u{ff21}',
+ '\u{ff3a}', SC_Upper), ('\u{ff3b}', '\u{ff3b}', SC_Close), ('\u{ff3d}', '\u{ff3d}',
+ SC_Close), ('\u{ff41}', '\u{ff5a}', SC_Lower), ('\u{ff5b}', '\u{ff5b}', SC_Close),
+ ('\u{ff5d}', '\u{ff5d}', SC_Close), ('\u{ff5f}', '\u{ff60}', SC_Close), ('\u{ff61}',
+ '\u{ff61}', SC_STerm), ('\u{ff62}', '\u{ff63}', SC_Close), ('\u{ff64}', '\u{ff64}',
+ SC_SContinue), ('\u{ff66}', '\u{ff9d}', SC_OLetter), ('\u{ff9e}', '\u{ff9f}', SC_Extend),
+ ('\u{ffa0}', '\u{ffbe}', SC_OLetter), ('\u{ffc2}', '\u{ffc7}', SC_OLetter), ('\u{ffca}',
+ '\u{ffcf}', SC_OLetter), ('\u{ffd2}', '\u{ffd7}', SC_OLetter), ('\u{ffda}', '\u{ffdc}',
+ SC_OLetter), ('\u{fff9}', '\u{fffb}', SC_Format), ('\u{10000}', '\u{1000b}', SC_OLetter),
+ ('\u{1000d}', '\u{10026}', SC_OLetter), ('\u{10028}', '\u{1003a}', SC_OLetter),
+ ('\u{1003c}', '\u{1003d}', SC_OLetter), ('\u{1003f}', '\u{1004d}', SC_OLetter),
+ ('\u{10050}', '\u{1005d}', SC_OLetter), ('\u{10080}', '\u{100fa}', SC_OLetter),
+ ('\u{10140}', '\u{10174}', SC_OLetter), ('\u{101fd}', '\u{101fd}', SC_Extend), ('\u{10280}',
+ '\u{1029c}', SC_OLetter), ('\u{102a0}', '\u{102d0}', SC_OLetter), ('\u{102e0}', '\u{102e0}',
+ SC_Extend), ('\u{10300}', '\u{1031f}', SC_OLetter), ('\u{1032d}', '\u{1034a}', SC_OLetter),
+ ('\u{10350}', '\u{10375}', SC_OLetter), ('\u{10376}', '\u{1037a}', SC_Extend), ('\u{10380}',
+ '\u{1039d}', SC_OLetter), ('\u{103a0}', '\u{103c3}', SC_OLetter), ('\u{103c8}', '\u{103cf}',
+ SC_OLetter), ('\u{103d1}', '\u{103d5}', SC_OLetter), ('\u{10400}', '\u{10427}', SC_Upper),
+ ('\u{10428}', '\u{1044f}', SC_Lower), ('\u{10450}', '\u{1049d}', SC_OLetter), ('\u{104a0}',
+ '\u{104a9}', SC_Numeric), ('\u{104b0}', '\u{104d3}', SC_Upper), ('\u{104d8}', '\u{104fb}',
+ SC_Lower), ('\u{10500}', '\u{10527}', SC_OLetter), ('\u{10530}', '\u{10563}', SC_OLetter),
+ ('\u{10600}', '\u{10736}', SC_OLetter), ('\u{10740}', '\u{10755}', SC_OLetter),
+ ('\u{10760}', '\u{10767}', SC_OLetter), ('\u{10800}', '\u{10805}', SC_OLetter),
+ ('\u{10808}', '\u{10808}', SC_OLetter), ('\u{1080a}', '\u{10835}', SC_OLetter),
+ ('\u{10837}', '\u{10838}', SC_OLetter), ('\u{1083c}', '\u{1083c}', SC_OLetter),
+ ('\u{1083f}', '\u{10855}', SC_OLetter), ('\u{10860}', '\u{10876}', SC_OLetter),
+ ('\u{10880}', '\u{1089e}', SC_OLetter), ('\u{108e0}', '\u{108f2}', SC_OLetter),
+ ('\u{108f4}', '\u{108f5}', SC_OLetter), ('\u{10900}', '\u{10915}', SC_OLetter),
+ ('\u{10920}', '\u{10939}', SC_OLetter), ('\u{10980}', '\u{109b7}', SC_OLetter),
+ ('\u{109be}', '\u{109bf}', SC_OLetter), ('\u{10a00}', '\u{10a00}', SC_OLetter),
+ ('\u{10a01}', '\u{10a03}', SC_Extend), ('\u{10a05}', '\u{10a06}', SC_Extend), ('\u{10a0c}',
+ '\u{10a0f}', SC_Extend), ('\u{10a10}', '\u{10a13}', SC_OLetter), ('\u{10a15}', '\u{10a17}',
+ SC_OLetter), ('\u{10a19}', '\u{10a35}', SC_OLetter), ('\u{10a38}', '\u{10a3a}', SC_Extend),
+ ('\u{10a3f}', '\u{10a3f}', SC_Extend), ('\u{10a56}', '\u{10a57}', SC_STerm), ('\u{10a60}',
+ '\u{10a7c}', SC_OLetter), ('\u{10a80}', '\u{10a9c}', SC_OLetter), ('\u{10ac0}', '\u{10ac7}',
+ SC_OLetter), ('\u{10ac9}', '\u{10ae4}', SC_OLetter), ('\u{10ae5}', '\u{10ae6}', SC_Extend),
+ ('\u{10b00}', '\u{10b35}', SC_OLetter), ('\u{10b40}', '\u{10b55}', SC_OLetter),
+ ('\u{10b60}', '\u{10b72}', SC_OLetter), ('\u{10b80}', '\u{10b91}', SC_OLetter),
+ ('\u{10c00}', '\u{10c48}', SC_OLetter), ('\u{10c80}', '\u{10cb2}', SC_Upper), ('\u{10cc0}',
+ '\u{10cf2}', SC_Lower), ('\u{10d00}', '\u{10d23}', SC_OLetter), ('\u{10d24}', '\u{10d27}',
+ SC_Extend), ('\u{10d30}', '\u{10d39}', SC_Numeric), ('\u{10f00}', '\u{10f1c}', SC_OLetter),
+ ('\u{10f27}', '\u{10f27}', SC_OLetter), ('\u{10f30}', '\u{10f45}', SC_OLetter),
+ ('\u{10f46}', '\u{10f50}', SC_Extend), ('\u{10f55}', '\u{10f59}', SC_STerm), ('\u{10fe0}',
+ '\u{10ff6}', SC_OLetter), ('\u{11000}', '\u{11002}', SC_Extend), ('\u{11003}', '\u{11037}',
+ SC_OLetter), ('\u{11038}', '\u{11046}', SC_Extend), ('\u{11047}', '\u{11048}', SC_STerm),
+ ('\u{11066}', '\u{1106f}', SC_Numeric), ('\u{1107f}', '\u{11082}', SC_Extend), ('\u{11083}',
+ '\u{110af}', SC_OLetter), ('\u{110b0}', '\u{110ba}', SC_Extend), ('\u{110bd}', '\u{110bd}',
+ SC_Format), ('\u{110be}', '\u{110c1}', SC_STerm), ('\u{110cd}', '\u{110cd}', SC_Format),
+ ('\u{110d0}', '\u{110e8}', SC_OLetter), ('\u{110f0}', '\u{110f9}', SC_Numeric),
+ ('\u{11100}', '\u{11102}', SC_Extend), ('\u{11103}', '\u{11126}', SC_OLetter), ('\u{11127}',
+ '\u{11134}', SC_Extend), ('\u{11136}', '\u{1113f}', SC_Numeric), ('\u{11141}', '\u{11143}',
+ SC_STerm), ('\u{11144}', '\u{11144}', SC_OLetter), ('\u{11145}', '\u{11146}', SC_Extend),
+ ('\u{11150}', '\u{11172}', SC_OLetter), ('\u{11173}', '\u{11173}', SC_Extend), ('\u{11176}',
+ '\u{11176}', SC_OLetter), ('\u{11180}', '\u{11182}', SC_Extend), ('\u{11183}', '\u{111b2}',
+ SC_OLetter), ('\u{111b3}', '\u{111c0}', SC_Extend), ('\u{111c1}', '\u{111c4}', SC_OLetter),
+ ('\u{111c5}', '\u{111c6}', SC_STerm), ('\u{111c9}', '\u{111cc}', SC_Extend), ('\u{111cd}',
+ '\u{111cd}', SC_STerm), ('\u{111d0}', '\u{111d9}', SC_Numeric), ('\u{111da}', '\u{111da}',
+ SC_OLetter), ('\u{111dc}', '\u{111dc}', SC_OLetter), ('\u{111de}', '\u{111df}', SC_STerm),
+ ('\u{11200}', '\u{11211}', SC_OLetter), ('\u{11213}', '\u{1122b}', SC_OLetter),
+ ('\u{1122c}', '\u{11237}', SC_Extend), ('\u{11238}', '\u{11239}', SC_STerm), ('\u{1123b}',
+ '\u{1123c}', SC_STerm), ('\u{1123e}', '\u{1123e}', SC_Extend), ('\u{11280}', '\u{11286}',
+ SC_OLetter), ('\u{11288}', '\u{11288}', SC_OLetter), ('\u{1128a}', '\u{1128d}', SC_OLetter),
+ ('\u{1128f}', '\u{1129d}', SC_OLetter), ('\u{1129f}', '\u{112a8}', SC_OLetter),
+ ('\u{112a9}', '\u{112a9}', SC_STerm), ('\u{112b0}', '\u{112de}', SC_OLetter), ('\u{112df}',
+ '\u{112ea}', SC_Extend), ('\u{112f0}', '\u{112f9}', SC_Numeric), ('\u{11300}', '\u{11303}',
+ SC_Extend), ('\u{11305}', '\u{1130c}', SC_OLetter), ('\u{1130f}', '\u{11310}', SC_OLetter),
+ ('\u{11313}', '\u{11328}', SC_OLetter), ('\u{1132a}', '\u{11330}', SC_OLetter),
+ ('\u{11332}', '\u{11333}', SC_OLetter), ('\u{11335}', '\u{11339}', SC_OLetter),
+ ('\u{1133b}', '\u{1133c}', SC_Extend), ('\u{1133d}', '\u{1133d}', SC_OLetter), ('\u{1133e}',
+ '\u{11344}', SC_Extend), ('\u{11347}', '\u{11348}', SC_Extend), ('\u{1134b}', '\u{1134d}',
+ SC_Extend), ('\u{11350}', '\u{11350}', SC_OLetter), ('\u{11357}', '\u{11357}', SC_Extend),
+ ('\u{1135d}', '\u{11361}', SC_OLetter), ('\u{11362}', '\u{11363}', SC_Extend), ('\u{11366}',
+ '\u{1136c}', SC_Extend), ('\u{11370}', '\u{11374}', SC_Extend), ('\u{11400}', '\u{11434}',
+ SC_OLetter), ('\u{11435}', '\u{11446}', SC_Extend), ('\u{11447}', '\u{1144a}', SC_OLetter),
+ ('\u{1144b}', '\u{1144c}', SC_STerm), ('\u{11450}', '\u{11459}', SC_Numeric), ('\u{1145e}',
+ '\u{1145e}', SC_Extend), ('\u{1145f}', '\u{1145f}', SC_OLetter), ('\u{11480}', '\u{114af}',
+ SC_OLetter), ('\u{114b0}', '\u{114c3}', SC_Extend), ('\u{114c4}', '\u{114c5}', SC_OLetter),
+ ('\u{114c7}', '\u{114c7}', SC_OLetter), ('\u{114d0}', '\u{114d9}', SC_Numeric),
+ ('\u{11580}', '\u{115ae}', SC_OLetter), ('\u{115af}', '\u{115b5}', SC_Extend), ('\u{115b8}',
+ '\u{115c0}', SC_Extend), ('\u{115c2}', '\u{115c3}', SC_STerm), ('\u{115c9}', '\u{115d7}',
+ SC_STerm), ('\u{115d8}', '\u{115db}', SC_OLetter), ('\u{115dc}', '\u{115dd}', SC_Extend),
+ ('\u{11600}', '\u{1162f}', SC_OLetter), ('\u{11630}', '\u{11640}', SC_Extend), ('\u{11641}',
+ '\u{11642}', SC_STerm), ('\u{11644}', '\u{11644}', SC_OLetter), ('\u{11650}', '\u{11659}',
+ SC_Numeric), ('\u{11680}', '\u{116aa}', SC_OLetter), ('\u{116ab}', '\u{116b7}', SC_Extend),
+ ('\u{116b8}', '\u{116b8}', SC_OLetter), ('\u{116c0}', '\u{116c9}', SC_Numeric),
+ ('\u{11700}', '\u{1171a}', SC_OLetter), ('\u{1171d}', '\u{1172b}', SC_Extend), ('\u{11730}',
+ '\u{11739}', SC_Numeric), ('\u{1173c}', '\u{1173e}', SC_STerm), ('\u{11800}', '\u{1182b}',
+ SC_OLetter), ('\u{1182c}', '\u{1183a}', SC_Extend), ('\u{118a0}', '\u{118bf}', SC_Upper),
+ ('\u{118c0}', '\u{118df}', SC_Lower), ('\u{118e0}', '\u{118e9}', SC_Numeric), ('\u{118ff}',
+ '\u{118ff}', SC_OLetter), ('\u{119a0}', '\u{119a7}', SC_OLetter), ('\u{119aa}', '\u{119d0}',
+ SC_OLetter), ('\u{119d1}', '\u{119d7}', SC_Extend), ('\u{119da}', '\u{119e0}', SC_Extend),
+ ('\u{119e1}', '\u{119e1}', SC_OLetter), ('\u{119e3}', '\u{119e3}', SC_OLetter),
+ ('\u{119e4}', '\u{119e4}', SC_Extend), ('\u{11a00}', '\u{11a00}', SC_OLetter), ('\u{11a01}',
+ '\u{11a0a}', SC_Extend), ('\u{11a0b}', '\u{11a32}', SC_OLetter), ('\u{11a33}', '\u{11a39}',
+ SC_Extend), ('\u{11a3a}', '\u{11a3a}', SC_OLetter), ('\u{11a3b}', '\u{11a3e}', SC_Extend),
+ ('\u{11a42}', '\u{11a43}', SC_STerm), ('\u{11a47}', '\u{11a47}', SC_Extend), ('\u{11a50}',
+ '\u{11a50}', SC_OLetter), ('\u{11a51}', '\u{11a5b}', SC_Extend), ('\u{11a5c}', '\u{11a89}',
+ SC_OLetter), ('\u{11a8a}', '\u{11a99}', SC_Extend), ('\u{11a9b}', '\u{11a9c}', SC_STerm),
+ ('\u{11a9d}', '\u{11a9d}', SC_OLetter), ('\u{11ac0}', '\u{11af8}', SC_OLetter),
+ ('\u{11c00}', '\u{11c08}', SC_OLetter), ('\u{11c0a}', '\u{11c2e}', SC_OLetter),
+ ('\u{11c2f}', '\u{11c36}', SC_Extend), ('\u{11c38}', '\u{11c3f}', SC_Extend), ('\u{11c40}',
+ '\u{11c40}', SC_OLetter), ('\u{11c41}', '\u{11c42}', SC_STerm), ('\u{11c50}', '\u{11c59}',
+ SC_Numeric), ('\u{11c72}', '\u{11c8f}', SC_OLetter), ('\u{11c92}', '\u{11ca7}', SC_Extend),
+ ('\u{11ca9}', '\u{11cb6}', SC_Extend), ('\u{11d00}', '\u{11d06}', SC_OLetter), ('\u{11d08}',
+ '\u{11d09}', SC_OLetter), ('\u{11d0b}', '\u{11d30}', SC_OLetter), ('\u{11d31}', '\u{11d36}',
+ SC_Extend), ('\u{11d3a}', '\u{11d3a}', SC_Extend), ('\u{11d3c}', '\u{11d3d}', SC_Extend),
+ ('\u{11d3f}', '\u{11d45}', SC_Extend), ('\u{11d46}', '\u{11d46}', SC_OLetter), ('\u{11d47}',
+ '\u{11d47}', SC_Extend), ('\u{11d50}', '\u{11d59}', SC_Numeric), ('\u{11d60}', '\u{11d65}',
+ SC_OLetter), ('\u{11d67}', '\u{11d68}', SC_OLetter), ('\u{11d6a}', '\u{11d89}', SC_OLetter),
+ ('\u{11d8a}', '\u{11d8e}', SC_Extend), ('\u{11d90}', '\u{11d91}', SC_Extend), ('\u{11d93}',
+ '\u{11d97}', SC_Extend), ('\u{11d98}', '\u{11d98}', SC_OLetter), ('\u{11da0}', '\u{11da9}',
+ SC_Numeric), ('\u{11ee0}', '\u{11ef2}', SC_OLetter), ('\u{11ef3}', '\u{11ef6}', SC_Extend),
+ ('\u{11ef7}', '\u{11ef8}', SC_STerm), ('\u{12000}', '\u{12399}', SC_OLetter), ('\u{12400}',
+ '\u{1246e}', SC_OLetter), ('\u{12480}', '\u{12543}', SC_OLetter), ('\u{13000}', '\u{1342e}',
+ SC_OLetter), ('\u{13430}', '\u{13438}', SC_Format), ('\u{14400}', '\u{14646}', SC_OLetter),
+ ('\u{16800}', '\u{16a38}', SC_OLetter), ('\u{16a40}', '\u{16a5e}', SC_OLetter),
+ ('\u{16a60}', '\u{16a69}', SC_Numeric), ('\u{16a6e}', '\u{16a6f}', SC_STerm), ('\u{16ad0}',
+ '\u{16aed}', SC_OLetter), ('\u{16af0}', '\u{16af4}', SC_Extend), ('\u{16af5}', '\u{16af5}',
+ SC_STerm), ('\u{16b00}', '\u{16b2f}', SC_OLetter), ('\u{16b30}', '\u{16b36}', SC_Extend),
+ ('\u{16b37}', '\u{16b38}', SC_STerm), ('\u{16b40}', '\u{16b43}', SC_OLetter), ('\u{16b44}',
+ '\u{16b44}', SC_STerm), ('\u{16b50}', '\u{16b59}', SC_Numeric), ('\u{16b63}', '\u{16b77}',
+ SC_OLetter), ('\u{16b7d}', '\u{16b8f}', SC_OLetter), ('\u{16e40}', '\u{16e5f}', SC_Upper),
+ ('\u{16e60}', '\u{16e7f}', SC_Lower), ('\u{16e98}', '\u{16e98}', SC_STerm), ('\u{16f00}',
+ '\u{16f4a}', SC_OLetter), ('\u{16f4f}', '\u{16f4f}', SC_Extend), ('\u{16f50}', '\u{16f50}',
+ SC_OLetter), ('\u{16f51}', '\u{16f87}', SC_Extend), ('\u{16f8f}', '\u{16f92}', SC_Extend),
+ ('\u{16f93}', '\u{16f9f}', SC_OLetter), ('\u{16fe0}', '\u{16fe1}', SC_OLetter),
+ ('\u{16fe3}', '\u{16fe3}', SC_OLetter), ('\u{17000}', '\u{187f7}', SC_OLetter),
+ ('\u{18800}', '\u{18af2}', SC_OLetter), ('\u{1b000}', '\u{1b11e}', SC_OLetter),
+ ('\u{1b150}', '\u{1b152}', SC_OLetter), ('\u{1b164}', '\u{1b167}', SC_OLetter),
+ ('\u{1b170}', '\u{1b2fb}', SC_OLetter), ('\u{1bc00}', '\u{1bc6a}', SC_OLetter),
+ ('\u{1bc70}', '\u{1bc7c}', SC_OLetter), ('\u{1bc80}', '\u{1bc88}', SC_OLetter),
+ ('\u{1bc90}', '\u{1bc99}', SC_OLetter), ('\u{1bc9d}', '\u{1bc9e}', SC_Extend), ('\u{1bc9f}',
+ '\u{1bc9f}', SC_STerm), ('\u{1bca0}', '\u{1bca3}', SC_Format), ('\u{1d165}', '\u{1d169}',
+ SC_Extend), ('\u{1d16d}', '\u{1d172}', SC_Extend), ('\u{1d173}', '\u{1d17a}', SC_Format),
+ ('\u{1d17b}', '\u{1d182}', SC_Extend), ('\u{1d185}', '\u{1d18b}', SC_Extend), ('\u{1d1aa}',
+ '\u{1d1ad}', SC_Extend), ('\u{1d242}', '\u{1d244}', SC_Extend), ('\u{1d400}', '\u{1d419}',
+ SC_Upper), ('\u{1d41a}', '\u{1d433}', SC_Lower), ('\u{1d434}', '\u{1d44d}', SC_Upper),
+ ('\u{1d44e}', '\u{1d454}', SC_Lower), ('\u{1d456}', '\u{1d467}', SC_Lower), ('\u{1d468}',
+ '\u{1d481}', SC_Upper), ('\u{1d482}', '\u{1d49b}', SC_Lower), ('\u{1d49c}', '\u{1d49c}',
+ SC_Upper), ('\u{1d49e}', '\u{1d49f}', SC_Upper), ('\u{1d4a2}', '\u{1d4a2}', SC_Upper),
+ ('\u{1d4a5}', '\u{1d4a6}', SC_Upper), ('\u{1d4a9}', '\u{1d4ac}', SC_Upper), ('\u{1d4ae}',
+ '\u{1d4b5}', SC_Upper), ('\u{1d4b6}', '\u{1d4b9}', SC_Lower), ('\u{1d4bb}', '\u{1d4bb}',
+ SC_Lower), ('\u{1d4bd}', '\u{1d4c3}', SC_Lower), ('\u{1d4c5}', '\u{1d4cf}', SC_Lower),
+ ('\u{1d4d0}', '\u{1d4e9}', SC_Upper), ('\u{1d4ea}', '\u{1d503}', SC_Lower), ('\u{1d504}',
+ '\u{1d505}', SC_Upper), ('\u{1d507}', '\u{1d50a}', SC_Upper), ('\u{1d50d}', '\u{1d514}',
+ SC_Upper), ('\u{1d516}', '\u{1d51c}', SC_Upper), ('\u{1d51e}', '\u{1d537}', SC_Lower),
+ ('\u{1d538}', '\u{1d539}', SC_Upper), ('\u{1d53b}', '\u{1d53e}', SC_Upper), ('\u{1d540}',
+ '\u{1d544}', SC_Upper), ('\u{1d546}', '\u{1d546}', SC_Upper), ('\u{1d54a}', '\u{1d550}',
+ SC_Upper), ('\u{1d552}', '\u{1d56b}', SC_Lower), ('\u{1d56c}', '\u{1d585}', SC_Upper),
+ ('\u{1d586}', '\u{1d59f}', SC_Lower), ('\u{1d5a0}', '\u{1d5b9}', SC_Upper), ('\u{1d5ba}',
+ '\u{1d5d3}', SC_Lower), ('\u{1d5d4}', '\u{1d5ed}', SC_Upper), ('\u{1d5ee}', '\u{1d607}',
+ SC_Lower), ('\u{1d608}', '\u{1d621}', SC_Upper), ('\u{1d622}', '\u{1d63b}', SC_Lower),
+ ('\u{1d63c}', '\u{1d655}', SC_Upper), ('\u{1d656}', '\u{1d66f}', SC_Lower), ('\u{1d670}',
+ '\u{1d689}', SC_Upper), ('\u{1d68a}', '\u{1d6a5}', SC_Lower), ('\u{1d6a8}', '\u{1d6c0}',
+ SC_Upper), ('\u{1d6c2}', '\u{1d6da}', SC_Lower), ('\u{1d6dc}', '\u{1d6e1}', SC_Lower),
+ ('\u{1d6e2}', '\u{1d6fa}', SC_Upper), ('\u{1d6fc}', '\u{1d714}', SC_Lower), ('\u{1d716}',
+ '\u{1d71b}', SC_Lower), ('\u{1d71c}', '\u{1d734}', SC_Upper), ('\u{1d736}', '\u{1d74e}',
+ SC_Lower), ('\u{1d750}', '\u{1d755}', SC_Lower), ('\u{1d756}', '\u{1d76e}', SC_Upper),
+ ('\u{1d770}', '\u{1d788}', SC_Lower), ('\u{1d78a}', '\u{1d78f}', SC_Lower), ('\u{1d790}',
+ '\u{1d7a8}', SC_Upper), ('\u{1d7aa}', '\u{1d7c2}', SC_Lower), ('\u{1d7c4}', '\u{1d7c9}',
+ SC_Lower), ('\u{1d7ca}', '\u{1d7ca}', SC_Upper), ('\u{1d7cb}', '\u{1d7cb}', SC_Lower),
+ ('\u{1d7ce}', '\u{1d7ff}', SC_Numeric), ('\u{1da00}', '\u{1da36}', SC_Extend), ('\u{1da3b}',
+ '\u{1da6c}', SC_Extend), ('\u{1da75}', '\u{1da75}', SC_Extend), ('\u{1da84}', '\u{1da84}',
+ SC_Extend), ('\u{1da88}', '\u{1da88}', SC_STerm), ('\u{1da9b}', '\u{1da9f}', SC_Extend),
+ ('\u{1daa1}', '\u{1daaf}', SC_Extend), ('\u{1e000}', '\u{1e006}', SC_Extend), ('\u{1e008}',
+ '\u{1e018}', SC_Extend), ('\u{1e01b}', '\u{1e021}', SC_Extend), ('\u{1e023}', '\u{1e024}',
+ SC_Extend), ('\u{1e026}', '\u{1e02a}', SC_Extend), ('\u{1e100}', '\u{1e12c}', SC_OLetter),
+ ('\u{1e130}', '\u{1e136}', SC_Extend), ('\u{1e137}', '\u{1e13d}', SC_OLetter), ('\u{1e140}',
+ '\u{1e149}', SC_Numeric), ('\u{1e14e}', '\u{1e14e}', SC_OLetter), ('\u{1e2c0}', '\u{1e2eb}',
+ SC_OLetter), ('\u{1e2ec}', '\u{1e2ef}', SC_Extend), ('\u{1e2f0}', '\u{1e2f9}', SC_Numeric),
+ ('\u{1e800}', '\u{1e8c4}', SC_OLetter), ('\u{1e8d0}', '\u{1e8d6}', SC_Extend), ('\u{1e900}',
+ '\u{1e921}', SC_Upper), ('\u{1e922}', '\u{1e943}', SC_Lower), ('\u{1e944}', '\u{1e94a}',
+ SC_Extend), ('\u{1e94b}', '\u{1e94b}', SC_OLetter), ('\u{1e950}', '\u{1e959}', SC_Numeric),
+ ('\u{1ee00}', '\u{1ee03}', SC_OLetter), ('\u{1ee05}', '\u{1ee1f}', SC_OLetter),
+ ('\u{1ee21}', '\u{1ee22}', SC_OLetter), ('\u{1ee24}', '\u{1ee24}', SC_OLetter),
+ ('\u{1ee27}', '\u{1ee27}', SC_OLetter), ('\u{1ee29}', '\u{1ee32}', SC_OLetter),
+ ('\u{1ee34}', '\u{1ee37}', SC_OLetter), ('\u{1ee39}', '\u{1ee39}', SC_OLetter),
+ ('\u{1ee3b}', '\u{1ee3b}', SC_OLetter), ('\u{1ee42}', '\u{1ee42}', SC_OLetter),
+ ('\u{1ee47}', '\u{1ee47}', SC_OLetter), ('\u{1ee49}', '\u{1ee49}', SC_OLetter),
+ ('\u{1ee4b}', '\u{1ee4b}', SC_OLetter), ('\u{1ee4d}', '\u{1ee4f}', SC_OLetter),
+ ('\u{1ee51}', '\u{1ee52}', SC_OLetter), ('\u{1ee54}', '\u{1ee54}', SC_OLetter),
+ ('\u{1ee57}', '\u{1ee57}', SC_OLetter), ('\u{1ee59}', '\u{1ee59}', SC_OLetter),
+ ('\u{1ee5b}', '\u{1ee5b}', SC_OLetter), ('\u{1ee5d}', '\u{1ee5d}', SC_OLetter),
+ ('\u{1ee5f}', '\u{1ee5f}', SC_OLetter), ('\u{1ee61}', '\u{1ee62}', SC_OLetter),
+ ('\u{1ee64}', '\u{1ee64}', SC_OLetter), ('\u{1ee67}', '\u{1ee6a}', SC_OLetter),
+ ('\u{1ee6c}', '\u{1ee72}', SC_OLetter), ('\u{1ee74}', '\u{1ee77}', SC_OLetter),
+ ('\u{1ee79}', '\u{1ee7c}', SC_OLetter), ('\u{1ee7e}', '\u{1ee7e}', SC_OLetter),
+ ('\u{1ee80}', '\u{1ee89}', SC_OLetter), ('\u{1ee8b}', '\u{1ee9b}', SC_OLetter),
+ ('\u{1eea1}', '\u{1eea3}', SC_OLetter), ('\u{1eea5}', '\u{1eea9}', SC_OLetter),
+ ('\u{1eeab}', '\u{1eebb}', SC_OLetter), ('\u{1f130}', '\u{1f149}', SC_Upper), ('\u{1f150}',
+ '\u{1f169}', SC_Upper), ('\u{1f170}', '\u{1f189}', SC_Upper), ('\u{1f676}', '\u{1f678}',
+ SC_Close), ('\u{20000}', '\u{2a6d6}', SC_OLetter), ('\u{2a700}', '\u{2b734}', SC_OLetter),
+ ('\u{2b740}', '\u{2b81d}', SC_OLetter), ('\u{2b820}', '\u{2cea1}', SC_OLetter),
+ ('\u{2ceb0}', '\u{2ebe0}', SC_OLetter), ('\u{2f800}', '\u{2fa1d}', SC_OLetter),
+ ('\u{e0001}', '\u{e0001}', SC_Format), ('\u{e0020}', '\u{e007f}', SC_Extend), ('\u{e0100}',
+ '\u{e01ef}', SC_Extend)
+ ];
+
+}
diff --git a/unicode-segmentation/src/test.rs b/unicode-segmentation/src/test.rs
new file mode 100644
index 0000000..75b77c5
--- /dev/null
+++ b/unicode-segmentation/src/test.rs
@@ -0,0 +1,197 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::UnicodeSegmentation;
+
+use std::prelude::v1::*;
+
+#[test]
+fn test_graphemes() {
+ use testdata::{TEST_SAME, TEST_DIFF};
+
+ pub const EXTRA_DIFF: &'static [(&'static str,
+ &'static [&'static str],
+ &'static [&'static str])] = &[
+ // Official test suite doesn't include two Prepend chars between two other chars.
+ ("\u{20}\u{600}\u{600}\u{20}",
+ &["\u{20}", "\u{600}\u{600}\u{20}"],
+ &["\u{20}", "\u{600}", "\u{600}", "\u{20}"]),
+
+ // Test for Prepend followed by two Any chars
+ ("\u{600}\u{20}\u{20}",
+ &["\u{600}\u{20}", "\u{20}"],
+ &["\u{600}", "\u{20}", "\u{20}"]),
+ ];
+
+ pub const EXTRA_SAME: &'static [(&'static str, &'static [&'static str])] = &[
+ // family emoji (more than two emoji joined by ZWJ)
+ ("\u{1f468}\u{200d}\u{1f467}\u{200d}\u{1f466}",
+ &["\u{1f468}\u{200d}\u{1f467}\u{200d}\u{1f466}"]),
+ // cartwheel emoji followed by two fitzpatrick skin tone modifiers
+ // (test case from issue #19)
+ ("\u{1F938}\u{1F3FE}\u{1F3FE}",
+ &["\u{1F938}\u{1F3FE}\u{1F3FE}"]),
+ ];
+
+ for &(s, g) in TEST_SAME.iter().chain(EXTRA_SAME) {
+ // test forward iterator
+ assert!(UnicodeSegmentation::graphemes(s, true).eq(g.iter().cloned()));
+ assert!(UnicodeSegmentation::graphemes(s, false).eq(g.iter().cloned()));
+
+ // test reverse iterator
+ assert!(UnicodeSegmentation::graphemes(s, true).rev().eq(g.iter().rev().cloned()));
+ assert!(UnicodeSegmentation::graphemes(s, false).rev().eq(g.iter().rev().cloned()));
+ }
+
+ for &(s, gt, gf) in TEST_DIFF.iter().chain(EXTRA_DIFF) {
+ // test forward iterator
+ assert!(UnicodeSegmentation::graphemes(s, true).eq(gt.iter().cloned()));
+ assert!(UnicodeSegmentation::graphemes(s, false).eq(gf.iter().cloned()));
+
+ // test reverse iterator
+ assert!(UnicodeSegmentation::graphemes(s, true).rev().eq(gt.iter().rev().cloned()));
+ assert!(UnicodeSegmentation::graphemes(s, false).rev().eq(gf.iter().rev().cloned()));
+ }
+
+ // test the indices iterators
+ let s = "a̐éö̲\r\n";
+ let gr_inds = UnicodeSegmentation::grapheme_indices(s, true).collect::<Vec<(usize, &str)>>();
+ let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")];
+ assert_eq!(gr_inds, b);
+ let gr_inds = UnicodeSegmentation::grapheme_indices(s, true).rev().collect::<Vec<(usize, &str)>>();
+ let b: &[_] = &[(11, "\r\n"), (6, "ö̲"), (3, "é"), (0, "a̐")];
+ assert_eq!(gr_inds, b);
+ let mut gr_inds_iter = UnicodeSegmentation::grapheme_indices(s, true);
+ {
+ let gr_inds = gr_inds_iter.by_ref();
+ let e1 = gr_inds.size_hint();
+ assert_eq!(e1, (1, Some(13)));
+ let c = gr_inds.count();
+ assert_eq!(c, 4);
+ }
+ let e2 = gr_inds_iter.size_hint();
+ assert_eq!(e2, (0, Some(0)));
+
+ // make sure the reverse iterator does the right thing with "\n" at beginning of string
+ let s = "\n\r\n\r";
+ let gr = UnicodeSegmentation::graphemes(s, true).rev().collect::<Vec<&str>>();
+ let b: &[_] = &["\r", "\r\n", "\n"];
+ assert_eq!(gr, b);
+}
+
+#[test]
+fn test_words() {
+ use testdata::TEST_WORD;
+
+ // Unicode's official tests don't really test longer chains of flag emoji
+ // TODO This could be improved with more tests like flag emoji with interspersed Extend chars and ZWJ
+ const EXTRA_TESTS: &'static [(&'static str, &'static [&'static str])] = &[
+ ("🇦🇫🇦🇽🇦🇱🇩🇿🇦🇸🇦🇩🇦🇴", &["🇦🇫", "🇦🇽", "🇦🇱", "🇩🇿", "🇦🇸", "🇦🇩", "🇦🇴"]),
+ ("🇦🇫🇦🇽🇦🇱🇩🇿🇦🇸🇦🇩🇦", &["🇦🇫", "🇦🇽", "🇦🇱", "🇩🇿", "🇦🇸", "🇦🇩", "🇦"]),
+ ("🇦a🇫🇦🇽a🇦🇱🇩🇿🇦🇸🇦🇩🇦", &["🇦", "a", "🇫🇦", "🇽", "a", "🇦🇱", "🇩🇿", "🇦🇸", "🇦🇩", "🇦"]),
+ ("\u{1f468}\u{200d}\u{1f468}\u{200d}\u{1f466}", &["\u{1f468}\u{200d}\u{1f468}\u{200d}\u{1f466}"]),
+ ("😌👎🏼", &["😌", "👎🏼"]),
+ // perhaps wrong, spaces should not be included?
+ ("hello world", &["hello", " ", "world"]),
+ ("🇨🇦🇨🇭🇿🇲🇿 hi", &["🇨🇦", "🇨🇭", "🇿🇲", "🇿", " ", "hi"]),
+ ];
+ for &(s, w) in TEST_WORD.iter().chain(EXTRA_TESTS.iter()) {
+ macro_rules! assert_ {
+ ($test:expr, $exp:expr, $name:expr) => {
+ // collect into vector for better diagnostics in failure case
+ let testing = $test.collect::<Vec<_>>();
+ let expected = $exp.collect::<Vec<_>>();
+ assert_eq!(testing, expected, "{} test for testcase ({:?}, {:?}) failed.", $name, s, w)
+ }
+ }
+ // test forward iterator
+ assert_!(s.split_word_bounds(),
+ w.iter().cloned(),
+ "Forward word boundaries");
+
+ // test reverse iterator
+ assert_!(s.split_word_bounds().rev(),
+ w.iter().rev().cloned(),
+ "Reverse word boundaries");
+
+ // generate offsets from word string lengths
+ let mut indices = vec![0];
+ for i in w.iter().cloned().map(|s| s.len()).scan(0, |t, n| { *t += n; Some(*t) }) {
+ indices.push(i);
+ }
+ indices.pop();
+ let indices = indices;
+
+ // test forward indices iterator
+ assert_!(s.split_word_bound_indices().map(|(l,_)| l),
+ indices.iter().cloned(),
+ "Forward word indices");
+
+ // test backward indices iterator
+ assert_!(s.split_word_bound_indices().rev().map(|(l,_)| l),
+ indices.iter().rev().cloned(),
+ "Reverse word indices");
+ }
+}
+
+
+#[test]
+fn test_sentences() {
+ use testdata::TEST_SENTENCE;
+
+ for &(s, w) in TEST_SENTENCE.iter() {
+ macro_rules! assert_ {
+ ($test:expr, $exp:expr, $name:expr) => {
+ // collect into vector for better diagnostics in failure case
+ let testing = $test.collect::<Vec<_>>();
+ let expected = $exp.collect::<Vec<_>>();
+ assert_eq!(testing, expected, "{} test for testcase ({:?}, {:?}) failed.", $name, s, w)
+ }
+ }
+
+ assert_!(s.split_sentence_bounds(),
+ w.iter().cloned(),
+ "Forward sentence boundaries");
+ }
+}
+
+quickcheck! {
+ fn quickcheck_forward_reverse_graphemes_extended(s: String) -> bool {
+ let a = s.graphemes(true).collect::<Vec<_>>();
+ let mut b = s.graphemes(true).rev().collect::<Vec<_>>();
+ b.reverse();
+ a == b
+ }
+
+ fn quickcheck_forward_reverse_graphemes_legacy(s: String) -> bool {
+ let a = s.graphemes(false).collect::<Vec<_>>();
+ let mut b = s.graphemes(false).rev().collect::<Vec<_>>();
+ b.reverse();
+ a == b
+ }
+
+ fn quickcheck_join_graphemes(s: String) -> bool {
+ let a = s.graphemes(true).collect::<String>();
+ let b = s.graphemes(false).collect::<String>();
+ a == s && b == s
+ }
+
+ fn quickcheck_forward_reverse_words(s: String) -> bool {
+ let a = s.split_word_bounds().collect::<Vec<_>>();
+ let mut b = s.split_word_bounds().rev().collect::<Vec<_>>();
+ b.reverse();
+ a == b
+ }
+
+ fn quickcheck_join_words(s: String) -> bool {
+ let a = s.split_word_bounds().collect::<String>();
+ a == s
+ }
+}
diff --git a/unicode-segmentation/src/testdata.rs b/unicode-segmentation/src/testdata.rs
new file mode 100644
index 0000000..b0402fa
--- /dev/null
+++ b/unicode-segmentation/src/testdata.rs
@@ -0,0 +1,2122 @@
+// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly
+
+#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
+ // official Unicode test data
+ // http://www.unicode.org/Public/12.0.0/ucd/auxiliary/GraphemeBreakTest.txt
+ pub const TEST_SAME: &'static [(&'static str, &'static [&'static str])] = &[
+ ("\u{20}\u{20}", &["\u{20}", "\u{20}"]), ("\u{20}\u{308}\u{20}", &["\u{20}\u{308}",
+ "\u{20}"]), ("\u{20}\u{d}", &["\u{20}", "\u{d}"]), ("\u{20}\u{308}\u{d}", &["\u{20}\u{308}",
+ "\u{d}"]), ("\u{20}\u{a}", &["\u{20}", "\u{a}"]), ("\u{20}\u{308}\u{a}", &["\u{20}\u{308}",
+ "\u{a}"]), ("\u{20}\u{1}", &["\u{20}", "\u{1}"]), ("\u{20}\u{308}\u{1}", &["\u{20}\u{308}",
+ "\u{1}"]), ("\u{20}\u{34f}", &["\u{20}\u{34f}"]), ("\u{20}\u{308}\u{34f}",
+ &["\u{20}\u{308}\u{34f}"]), ("\u{20}\u{1f1e6}", &["\u{20}", "\u{1f1e6}"]),
+ ("\u{20}\u{308}\u{1f1e6}", &["\u{20}\u{308}", "\u{1f1e6}"]), ("\u{20}\u{600}", &["\u{20}",
+ "\u{600}"]), ("\u{20}\u{308}\u{600}", &["\u{20}\u{308}", "\u{600}"]), ("\u{20}\u{1100}",
+ &["\u{20}", "\u{1100}"]), ("\u{20}\u{308}\u{1100}", &["\u{20}\u{308}", "\u{1100}"]),
+ ("\u{20}\u{1160}", &["\u{20}", "\u{1160}"]), ("\u{20}\u{308}\u{1160}", &["\u{20}\u{308}",
+ "\u{1160}"]), ("\u{20}\u{11a8}", &["\u{20}", "\u{11a8}"]), ("\u{20}\u{308}\u{11a8}",
+ &["\u{20}\u{308}", "\u{11a8}"]), ("\u{20}\u{ac00}", &["\u{20}", "\u{ac00}"]),
+ ("\u{20}\u{308}\u{ac00}", &["\u{20}\u{308}", "\u{ac00}"]), ("\u{20}\u{ac01}", &["\u{20}",
+ "\u{ac01}"]), ("\u{20}\u{308}\u{ac01}", &["\u{20}\u{308}", "\u{ac01}"]), ("\u{20}\u{231a}",
+ &["\u{20}", "\u{231a}"]), ("\u{20}\u{308}\u{231a}", &["\u{20}\u{308}", "\u{231a}"]),
+ ("\u{20}\u{300}", &["\u{20}\u{300}"]), ("\u{20}\u{308}\u{300}", &["\u{20}\u{308}\u{300}"]),
+ ("\u{20}\u{200d}", &["\u{20}\u{200d}"]), ("\u{20}\u{308}\u{200d}",
+ &["\u{20}\u{308}\u{200d}"]), ("\u{20}\u{378}", &["\u{20}", "\u{378}"]),
+ ("\u{20}\u{308}\u{378}", &["\u{20}\u{308}", "\u{378}"]), ("\u{d}\u{20}", &["\u{d}",
+ "\u{20}"]), ("\u{d}\u{308}\u{20}", &["\u{d}", "\u{308}", "\u{20}"]), ("\u{d}\u{d}",
+ &["\u{d}", "\u{d}"]), ("\u{d}\u{308}\u{d}", &["\u{d}", "\u{308}", "\u{d}"]), ("\u{d}\u{a}",
+ &["\u{d}\u{a}"]), ("\u{d}\u{308}\u{a}", &["\u{d}", "\u{308}", "\u{a}"]), ("\u{d}\u{1}",
+ &["\u{d}", "\u{1}"]), ("\u{d}\u{308}\u{1}", &["\u{d}", "\u{308}", "\u{1}"]),
+ ("\u{d}\u{34f}", &["\u{d}", "\u{34f}"]), ("\u{d}\u{308}\u{34f}", &["\u{d}",
+ "\u{308}\u{34f}"]), ("\u{d}\u{1f1e6}", &["\u{d}", "\u{1f1e6}"]), ("\u{d}\u{308}\u{1f1e6}",
+ &["\u{d}", "\u{308}", "\u{1f1e6}"]), ("\u{d}\u{600}", &["\u{d}", "\u{600}"]),
+ ("\u{d}\u{308}\u{600}", &["\u{d}", "\u{308}", "\u{600}"]), ("\u{d}\u{903}", &["\u{d}",
+ "\u{903}"]), ("\u{d}\u{1100}", &["\u{d}", "\u{1100}"]), ("\u{d}\u{308}\u{1100}", &["\u{d}",
+ "\u{308}", "\u{1100}"]), ("\u{d}\u{1160}", &["\u{d}", "\u{1160}"]), ("\u{d}\u{308}\u{1160}",
+ &["\u{d}", "\u{308}", "\u{1160}"]), ("\u{d}\u{11a8}", &["\u{d}", "\u{11a8}"]),
+ ("\u{d}\u{308}\u{11a8}", &["\u{d}", "\u{308}", "\u{11a8}"]), ("\u{d}\u{ac00}", &["\u{d}",
+ "\u{ac00}"]), ("\u{d}\u{308}\u{ac00}", &["\u{d}", "\u{308}", "\u{ac00}"]), ("\u{d}\u{ac01}",
+ &["\u{d}", "\u{ac01}"]), ("\u{d}\u{308}\u{ac01}", &["\u{d}", "\u{308}", "\u{ac01}"]),
+ ("\u{d}\u{231a}", &["\u{d}", "\u{231a}"]), ("\u{d}\u{308}\u{231a}", &["\u{d}", "\u{308}",
+ "\u{231a}"]), ("\u{d}\u{300}", &["\u{d}", "\u{300}"]), ("\u{d}\u{308}\u{300}", &["\u{d}",
+ "\u{308}\u{300}"]), ("\u{d}\u{200d}", &["\u{d}", "\u{200d}"]), ("\u{d}\u{308}\u{200d}",
+ &["\u{d}", "\u{308}\u{200d}"]), ("\u{d}\u{378}", &["\u{d}", "\u{378}"]),
+ ("\u{d}\u{308}\u{378}", &["\u{d}", "\u{308}", "\u{378}"]), ("\u{a}\u{20}", &["\u{a}",
+ "\u{20}"]), ("\u{a}\u{308}\u{20}", &["\u{a}", "\u{308}", "\u{20}"]), ("\u{a}\u{d}",
+ &["\u{a}", "\u{d}"]), ("\u{a}\u{308}\u{d}", &["\u{a}", "\u{308}", "\u{d}"]), ("\u{a}\u{a}",
+ &["\u{a}", "\u{a}"]), ("\u{a}\u{308}\u{a}", &["\u{a}", "\u{308}", "\u{a}"]), ("\u{a}\u{1}",
+ &["\u{a}", "\u{1}"]), ("\u{a}\u{308}\u{1}", &["\u{a}", "\u{308}", "\u{1}"]),
+ ("\u{a}\u{34f}", &["\u{a}", "\u{34f}"]), ("\u{a}\u{308}\u{34f}", &["\u{a}",
+ "\u{308}\u{34f}"]), ("\u{a}\u{1f1e6}", &["\u{a}", "\u{1f1e6}"]), ("\u{a}\u{308}\u{1f1e6}",
+ &["\u{a}", "\u{308}", "\u{1f1e6}"]), ("\u{a}\u{600}", &["\u{a}", "\u{600}"]),
+ ("\u{a}\u{308}\u{600}", &["\u{a}", "\u{308}", "\u{600}"]), ("\u{a}\u{903}", &["\u{a}",
+ "\u{903}"]), ("\u{a}\u{1100}", &["\u{a}", "\u{1100}"]), ("\u{a}\u{308}\u{1100}", &["\u{a}",
+ "\u{308}", "\u{1100}"]), ("\u{a}\u{1160}", &["\u{a}", "\u{1160}"]), ("\u{a}\u{308}\u{1160}",
+ &["\u{a}", "\u{308}", "\u{1160}"]), ("\u{a}\u{11a8}", &["\u{a}", "\u{11a8}"]),
+ ("\u{a}\u{308}\u{11a8}", &["\u{a}", "\u{308}", "\u{11a8}"]), ("\u{a}\u{ac00}", &["\u{a}",
+ "\u{ac00}"]), ("\u{a}\u{308}\u{ac00}", &["\u{a}", "\u{308}", "\u{ac00}"]), ("\u{a}\u{ac01}",
+ &["\u{a}", "\u{ac01}"]), ("\u{a}\u{308}\u{ac01}", &["\u{a}", "\u{308}", "\u{ac01}"]),
+ ("\u{a}\u{231a}", &["\u{a}", "\u{231a}"]), ("\u{a}\u{308}\u{231a}", &["\u{a}", "\u{308}",
+ "\u{231a}"]), ("\u{a}\u{300}", &["\u{a}", "\u{300}"]), ("\u{a}\u{308}\u{300}", &["\u{a}",
+ "\u{308}\u{300}"]), ("\u{a}\u{200d}", &["\u{a}", "\u{200d}"]), ("\u{a}\u{308}\u{200d}",
+ &["\u{a}", "\u{308}\u{200d}"]), ("\u{a}\u{378}", &["\u{a}", "\u{378}"]),
+ ("\u{a}\u{308}\u{378}", &["\u{a}", "\u{308}", "\u{378}"]), ("\u{1}\u{20}", &["\u{1}",
+ "\u{20}"]), ("\u{1}\u{308}\u{20}", &["\u{1}", "\u{308}", "\u{20}"]), ("\u{1}\u{d}",
+ &["\u{1}", "\u{d}"]), ("\u{1}\u{308}\u{d}", &["\u{1}", "\u{308}", "\u{d}"]), ("\u{1}\u{a}",
+ &["\u{1}", "\u{a}"]), ("\u{1}\u{308}\u{a}", &["\u{1}", "\u{308}", "\u{a}"]), ("\u{1}\u{1}",
+ &["\u{1}", "\u{1}"]), ("\u{1}\u{308}\u{1}", &["\u{1}", "\u{308}", "\u{1}"]),
+ ("\u{1}\u{34f}", &["\u{1}", "\u{34f}"]), ("\u{1}\u{308}\u{34f}", &["\u{1}",
+ "\u{308}\u{34f}"]), ("\u{1}\u{1f1e6}", &["\u{1}", "\u{1f1e6}"]), ("\u{1}\u{308}\u{1f1e6}",
+ &["\u{1}", "\u{308}", "\u{1f1e6}"]), ("\u{1}\u{600}", &["\u{1}", "\u{600}"]),
+ ("\u{1}\u{308}\u{600}", &["\u{1}", "\u{308}", "\u{600}"]), ("\u{1}\u{903}", &["\u{1}",
+ "\u{903}"]), ("\u{1}\u{1100}", &["\u{1}", "\u{1100}"]), ("\u{1}\u{308}\u{1100}", &["\u{1}",
+ "\u{308}", "\u{1100}"]), ("\u{1}\u{1160}", &["\u{1}", "\u{1160}"]), ("\u{1}\u{308}\u{1160}",
+ &["\u{1}", "\u{308}", "\u{1160}"]), ("\u{1}\u{11a8}", &["\u{1}", "\u{11a8}"]),
+ ("\u{1}\u{308}\u{11a8}", &["\u{1}", "\u{308}", "\u{11a8}"]), ("\u{1}\u{ac00}", &["\u{1}",
+ "\u{ac00}"]), ("\u{1}\u{308}\u{ac00}", &["\u{1}", "\u{308}", "\u{ac00}"]), ("\u{1}\u{ac01}",
+ &["\u{1}", "\u{ac01}"]), ("\u{1}\u{308}\u{ac01}", &["\u{1}", "\u{308}", "\u{ac01}"]),
+ ("\u{1}\u{231a}", &["\u{1}", "\u{231a}"]), ("\u{1}\u{308}\u{231a}", &["\u{1}", "\u{308}",
+ "\u{231a}"]), ("\u{1}\u{300}", &["\u{1}", "\u{300}"]), ("\u{1}\u{308}\u{300}", &["\u{1}",
+ "\u{308}\u{300}"]), ("\u{1}\u{200d}", &["\u{1}", "\u{200d}"]), ("\u{1}\u{308}\u{200d}",
+ &["\u{1}", "\u{308}\u{200d}"]), ("\u{1}\u{378}", &["\u{1}", "\u{378}"]),
+ ("\u{1}\u{308}\u{378}", &["\u{1}", "\u{308}", "\u{378}"]), ("\u{34f}\u{20}", &["\u{34f}",
+ "\u{20}"]), ("\u{34f}\u{308}\u{20}", &["\u{34f}\u{308}", "\u{20}"]), ("\u{34f}\u{d}",
+ &["\u{34f}", "\u{d}"]), ("\u{34f}\u{308}\u{d}", &["\u{34f}\u{308}", "\u{d}"]),
+ ("\u{34f}\u{a}", &["\u{34f}", "\u{a}"]), ("\u{34f}\u{308}\u{a}", &["\u{34f}\u{308}",
+ "\u{a}"]), ("\u{34f}\u{1}", &["\u{34f}", "\u{1}"]), ("\u{34f}\u{308}\u{1}",
+ &["\u{34f}\u{308}", "\u{1}"]), ("\u{34f}\u{34f}", &["\u{34f}\u{34f}"]),
+ ("\u{34f}\u{308}\u{34f}", &["\u{34f}\u{308}\u{34f}"]), ("\u{34f}\u{1f1e6}", &["\u{34f}",
+ "\u{1f1e6}"]), ("\u{34f}\u{308}\u{1f1e6}", &["\u{34f}\u{308}", "\u{1f1e6}"]),
+ ("\u{34f}\u{600}", &["\u{34f}", "\u{600}"]), ("\u{34f}\u{308}\u{600}", &["\u{34f}\u{308}",
+ "\u{600}"]), ("\u{34f}\u{1100}", &["\u{34f}", "\u{1100}"]), ("\u{34f}\u{308}\u{1100}",
+ &["\u{34f}\u{308}", "\u{1100}"]), ("\u{34f}\u{1160}", &["\u{34f}", "\u{1160}"]),
+ ("\u{34f}\u{308}\u{1160}", &["\u{34f}\u{308}", "\u{1160}"]), ("\u{34f}\u{11a8}",
+ &["\u{34f}", "\u{11a8}"]), ("\u{34f}\u{308}\u{11a8}", &["\u{34f}\u{308}", "\u{11a8}"]),
+ ("\u{34f}\u{ac00}", &["\u{34f}", "\u{ac00}"]), ("\u{34f}\u{308}\u{ac00}",
+ &["\u{34f}\u{308}", "\u{ac00}"]), ("\u{34f}\u{ac01}", &["\u{34f}", "\u{ac01}"]),
+ ("\u{34f}\u{308}\u{ac01}", &["\u{34f}\u{308}", "\u{ac01}"]), ("\u{34f}\u{231a}",
+ &["\u{34f}", "\u{231a}"]), ("\u{34f}\u{308}\u{231a}", &["\u{34f}\u{308}", "\u{231a}"]),
+ ("\u{34f}\u{300}", &["\u{34f}\u{300}"]), ("\u{34f}\u{308}\u{300}",
+ &["\u{34f}\u{308}\u{300}"]), ("\u{34f}\u{200d}", &["\u{34f}\u{200d}"]),
+ ("\u{34f}\u{308}\u{200d}", &["\u{34f}\u{308}\u{200d}"]), ("\u{34f}\u{378}", &["\u{34f}",
+ "\u{378}"]), ("\u{34f}\u{308}\u{378}", &["\u{34f}\u{308}", "\u{378}"]), ("\u{1f1e6}\u{20}",
+ &["\u{1f1e6}", "\u{20}"]), ("\u{1f1e6}\u{308}\u{20}", &["\u{1f1e6}\u{308}", "\u{20}"]),
+ ("\u{1f1e6}\u{d}", &["\u{1f1e6}", "\u{d}"]), ("\u{1f1e6}\u{308}\u{d}", &["\u{1f1e6}\u{308}",
+ "\u{d}"]), ("\u{1f1e6}\u{a}", &["\u{1f1e6}", "\u{a}"]), ("\u{1f1e6}\u{308}\u{a}",
+ &["\u{1f1e6}\u{308}", "\u{a}"]), ("\u{1f1e6}\u{1}", &["\u{1f1e6}", "\u{1}"]),
+ ("\u{1f1e6}\u{308}\u{1}", &["\u{1f1e6}\u{308}", "\u{1}"]), ("\u{1f1e6}\u{34f}",
+ &["\u{1f1e6}\u{34f}"]), ("\u{1f1e6}\u{308}\u{34f}", &["\u{1f1e6}\u{308}\u{34f}"]),
+ ("\u{1f1e6}\u{1f1e6}", &["\u{1f1e6}\u{1f1e6}"]), ("\u{1f1e6}\u{308}\u{1f1e6}",
+ &["\u{1f1e6}\u{308}", "\u{1f1e6}"]), ("\u{1f1e6}\u{600}", &["\u{1f1e6}", "\u{600}"]),
+ ("\u{1f1e6}\u{308}\u{600}", &["\u{1f1e6}\u{308}", "\u{600}"]), ("\u{1f1e6}\u{1100}",
+ &["\u{1f1e6}", "\u{1100}"]), ("\u{1f1e6}\u{308}\u{1100}", &["\u{1f1e6}\u{308}",
+ "\u{1100}"]), ("\u{1f1e6}\u{1160}", &["\u{1f1e6}", "\u{1160}"]),
+ ("\u{1f1e6}\u{308}\u{1160}", &["\u{1f1e6}\u{308}", "\u{1160}"]), ("\u{1f1e6}\u{11a8}",
+ &["\u{1f1e6}", "\u{11a8}"]), ("\u{1f1e6}\u{308}\u{11a8}", &["\u{1f1e6}\u{308}",
+ "\u{11a8}"]), ("\u{1f1e6}\u{ac00}", &["\u{1f1e6}", "\u{ac00}"]),
+ ("\u{1f1e6}\u{308}\u{ac00}", &["\u{1f1e6}\u{308}", "\u{ac00}"]), ("\u{1f1e6}\u{ac01}",
+ &["\u{1f1e6}", "\u{ac01}"]), ("\u{1f1e6}\u{308}\u{ac01}", &["\u{1f1e6}\u{308}",
+ "\u{ac01}"]), ("\u{1f1e6}\u{231a}", &["\u{1f1e6}", "\u{231a}"]),
+ ("\u{1f1e6}\u{308}\u{231a}", &["\u{1f1e6}\u{308}", "\u{231a}"]), ("\u{1f1e6}\u{300}",
+ &["\u{1f1e6}\u{300}"]), ("\u{1f1e6}\u{308}\u{300}", &["\u{1f1e6}\u{308}\u{300}"]),
+ ("\u{1f1e6}\u{200d}", &["\u{1f1e6}\u{200d}"]), ("\u{1f1e6}\u{308}\u{200d}",
+ &["\u{1f1e6}\u{308}\u{200d}"]), ("\u{1f1e6}\u{378}", &["\u{1f1e6}", "\u{378}"]),
+ ("\u{1f1e6}\u{308}\u{378}", &["\u{1f1e6}\u{308}", "\u{378}"]), ("\u{600}\u{308}\u{20}",
+ &["\u{600}\u{308}", "\u{20}"]), ("\u{600}\u{d}", &["\u{600}", "\u{d}"]),
+ ("\u{600}\u{308}\u{d}", &["\u{600}\u{308}", "\u{d}"]), ("\u{600}\u{a}", &["\u{600}",
+ "\u{a}"]), ("\u{600}\u{308}\u{a}", &["\u{600}\u{308}", "\u{a}"]), ("\u{600}\u{1}",
+ &["\u{600}", "\u{1}"]), ("\u{600}\u{308}\u{1}", &["\u{600}\u{308}", "\u{1}"]),
+ ("\u{600}\u{34f}", &["\u{600}\u{34f}"]), ("\u{600}\u{308}\u{34f}",
+ &["\u{600}\u{308}\u{34f}"]), ("\u{600}\u{308}\u{1f1e6}", &["\u{600}\u{308}", "\u{1f1e6}"]),
+ ("\u{600}\u{308}\u{600}", &["\u{600}\u{308}", "\u{600}"]), ("\u{600}\u{308}\u{1100}",
+ &["\u{600}\u{308}", "\u{1100}"]), ("\u{600}\u{308}\u{1160}", &["\u{600}\u{308}",
+ "\u{1160}"]), ("\u{600}\u{308}\u{11a8}", &["\u{600}\u{308}", "\u{11a8}"]),
+ ("\u{600}\u{308}\u{ac00}", &["\u{600}\u{308}", "\u{ac00}"]), ("\u{600}\u{308}\u{ac01}",
+ &["\u{600}\u{308}", "\u{ac01}"]), ("\u{600}\u{308}\u{231a}", &["\u{600}\u{308}",
+ "\u{231a}"]), ("\u{600}\u{300}", &["\u{600}\u{300}"]), ("\u{600}\u{308}\u{300}",
+ &["\u{600}\u{308}\u{300}"]), ("\u{600}\u{200d}", &["\u{600}\u{200d}"]),
+ ("\u{600}\u{308}\u{200d}", &["\u{600}\u{308}\u{200d}"]), ("\u{600}\u{308}\u{378}",
+ &["\u{600}\u{308}", "\u{378}"]), ("\u{903}\u{20}", &["\u{903}", "\u{20}"]),
+ ("\u{903}\u{308}\u{20}", &["\u{903}\u{308}", "\u{20}"]), ("\u{903}\u{d}", &["\u{903}",
+ "\u{d}"]), ("\u{903}\u{308}\u{d}", &["\u{903}\u{308}", "\u{d}"]), ("\u{903}\u{a}",
+ &["\u{903}", "\u{a}"]), ("\u{903}\u{308}\u{a}", &["\u{903}\u{308}", "\u{a}"]),
+ ("\u{903}\u{1}", &["\u{903}", "\u{1}"]), ("\u{903}\u{308}\u{1}", &["\u{903}\u{308}",
+ "\u{1}"]), ("\u{903}\u{34f}", &["\u{903}\u{34f}"]), ("\u{903}\u{308}\u{34f}",
+ &["\u{903}\u{308}\u{34f}"]), ("\u{903}\u{1f1e6}", &["\u{903}", "\u{1f1e6}"]),
+ ("\u{903}\u{308}\u{1f1e6}", &["\u{903}\u{308}", "\u{1f1e6}"]), ("\u{903}\u{600}",
+ &["\u{903}", "\u{600}"]), ("\u{903}\u{308}\u{600}", &["\u{903}\u{308}", "\u{600}"]),
+ ("\u{903}\u{1100}", &["\u{903}", "\u{1100}"]), ("\u{903}\u{308}\u{1100}",
+ &["\u{903}\u{308}", "\u{1100}"]), ("\u{903}\u{1160}", &["\u{903}", "\u{1160}"]),
+ ("\u{903}\u{308}\u{1160}", &["\u{903}\u{308}", "\u{1160}"]), ("\u{903}\u{11a8}",
+ &["\u{903}", "\u{11a8}"]), ("\u{903}\u{308}\u{11a8}", &["\u{903}\u{308}", "\u{11a8}"]),
+ ("\u{903}\u{ac00}", &["\u{903}", "\u{ac00}"]), ("\u{903}\u{308}\u{ac00}",
+ &["\u{903}\u{308}", "\u{ac00}"]), ("\u{903}\u{ac01}", &["\u{903}", "\u{ac01}"]),
+ ("\u{903}\u{308}\u{ac01}", &["\u{903}\u{308}", "\u{ac01}"]), ("\u{903}\u{231a}",
+ &["\u{903}", "\u{231a}"]), ("\u{903}\u{308}\u{231a}", &["\u{903}\u{308}", "\u{231a}"]),
+ ("\u{903}\u{300}", &["\u{903}\u{300}"]), ("\u{903}\u{308}\u{300}",
+ &["\u{903}\u{308}\u{300}"]), ("\u{903}\u{200d}", &["\u{903}\u{200d}"]),
+ ("\u{903}\u{308}\u{200d}", &["\u{903}\u{308}\u{200d}"]), ("\u{903}\u{378}", &["\u{903}",
+ "\u{378}"]), ("\u{903}\u{308}\u{378}", &["\u{903}\u{308}", "\u{378}"]), ("\u{1100}\u{20}",
+ &["\u{1100}", "\u{20}"]), ("\u{1100}\u{308}\u{20}", &["\u{1100}\u{308}", "\u{20}"]),
+ ("\u{1100}\u{d}", &["\u{1100}", "\u{d}"]), ("\u{1100}\u{308}\u{d}", &["\u{1100}\u{308}",
+ "\u{d}"]), ("\u{1100}\u{a}", &["\u{1100}", "\u{a}"]), ("\u{1100}\u{308}\u{a}",
+ &["\u{1100}\u{308}", "\u{a}"]), ("\u{1100}\u{1}", &["\u{1100}", "\u{1}"]),
+ ("\u{1100}\u{308}\u{1}", &["\u{1100}\u{308}", "\u{1}"]), ("\u{1100}\u{34f}",
+ &["\u{1100}\u{34f}"]), ("\u{1100}\u{308}\u{34f}", &["\u{1100}\u{308}\u{34f}"]),
+ ("\u{1100}\u{1f1e6}", &["\u{1100}", "\u{1f1e6}"]), ("\u{1100}\u{308}\u{1f1e6}",
+ &["\u{1100}\u{308}", "\u{1f1e6}"]), ("\u{1100}\u{600}", &["\u{1100}", "\u{600}"]),
+ ("\u{1100}\u{308}\u{600}", &["\u{1100}\u{308}", "\u{600}"]), ("\u{1100}\u{1100}",
+ &["\u{1100}\u{1100}"]), ("\u{1100}\u{308}\u{1100}", &["\u{1100}\u{308}", "\u{1100}"]),
+ ("\u{1100}\u{1160}", &["\u{1100}\u{1160}"]), ("\u{1100}\u{308}\u{1160}",
+ &["\u{1100}\u{308}", "\u{1160}"]), ("\u{1100}\u{11a8}", &["\u{1100}", "\u{11a8}"]),
+ ("\u{1100}\u{308}\u{11a8}", &["\u{1100}\u{308}", "\u{11a8}"]), ("\u{1100}\u{ac00}",
+ &["\u{1100}\u{ac00}"]), ("\u{1100}\u{308}\u{ac00}", &["\u{1100}\u{308}", "\u{ac00}"]),
+ ("\u{1100}\u{ac01}", &["\u{1100}\u{ac01}"]), ("\u{1100}\u{308}\u{ac01}",
+ &["\u{1100}\u{308}", "\u{ac01}"]), ("\u{1100}\u{231a}", &["\u{1100}", "\u{231a}"]),
+ ("\u{1100}\u{308}\u{231a}", &["\u{1100}\u{308}", "\u{231a}"]), ("\u{1100}\u{300}",
+ &["\u{1100}\u{300}"]), ("\u{1100}\u{308}\u{300}", &["\u{1100}\u{308}\u{300}"]),
+ ("\u{1100}\u{200d}", &["\u{1100}\u{200d}"]), ("\u{1100}\u{308}\u{200d}",
+ &["\u{1100}\u{308}\u{200d}"]), ("\u{1100}\u{378}", &["\u{1100}", "\u{378}"]),
+ ("\u{1100}\u{308}\u{378}", &["\u{1100}\u{308}", "\u{378}"]), ("\u{1160}\u{20}",
+ &["\u{1160}", "\u{20}"]), ("\u{1160}\u{308}\u{20}", &["\u{1160}\u{308}", "\u{20}"]),
+ ("\u{1160}\u{d}", &["\u{1160}", "\u{d}"]), ("\u{1160}\u{308}\u{d}", &["\u{1160}\u{308}",
+ "\u{d}"]), ("\u{1160}\u{a}", &["\u{1160}", "\u{a}"]), ("\u{1160}\u{308}\u{a}",
+ &["\u{1160}\u{308}", "\u{a}"]), ("\u{1160}\u{1}", &["\u{1160}", "\u{1}"]),
+ ("\u{1160}\u{308}\u{1}", &["\u{1160}\u{308}", "\u{1}"]), ("\u{1160}\u{34f}",
+ &["\u{1160}\u{34f}"]), ("\u{1160}\u{308}\u{34f}", &["\u{1160}\u{308}\u{34f}"]),
+ ("\u{1160}\u{1f1e6}", &["\u{1160}", "\u{1f1e6}"]), ("\u{1160}\u{308}\u{1f1e6}",
+ &["\u{1160}\u{308}", "\u{1f1e6}"]), ("\u{1160}\u{600}", &["\u{1160}", "\u{600}"]),
+ ("\u{1160}\u{308}\u{600}", &["\u{1160}\u{308}", "\u{600}"]), ("\u{1160}\u{1100}",
+ &["\u{1160}", "\u{1100}"]), ("\u{1160}\u{308}\u{1100}", &["\u{1160}\u{308}", "\u{1100}"]),
+ ("\u{1160}\u{1160}", &["\u{1160}\u{1160}"]), ("\u{1160}\u{308}\u{1160}",
+ &["\u{1160}\u{308}", "\u{1160}"]), ("\u{1160}\u{11a8}", &["\u{1160}\u{11a8}"]),
+ ("\u{1160}\u{308}\u{11a8}", &["\u{1160}\u{308}", "\u{11a8}"]), ("\u{1160}\u{ac00}",
+ &["\u{1160}", "\u{ac00}"]), ("\u{1160}\u{308}\u{ac00}", &["\u{1160}\u{308}", "\u{ac00}"]),
+ ("\u{1160}\u{ac01}", &["\u{1160}", "\u{ac01}"]), ("\u{1160}\u{308}\u{ac01}",
+ &["\u{1160}\u{308}", "\u{ac01}"]), ("\u{1160}\u{231a}", &["\u{1160}", "\u{231a}"]),
+ ("\u{1160}\u{308}\u{231a}", &["\u{1160}\u{308}", "\u{231a}"]), ("\u{1160}\u{300}",
+ &["\u{1160}\u{300}"]), ("\u{1160}\u{308}\u{300}", &["\u{1160}\u{308}\u{300}"]),
+ ("\u{1160}\u{200d}", &["\u{1160}\u{200d}"]), ("\u{1160}\u{308}\u{200d}",
+ &["\u{1160}\u{308}\u{200d}"]), ("\u{1160}\u{378}", &["\u{1160}", "\u{378}"]),
+ ("\u{1160}\u{308}\u{378}", &["\u{1160}\u{308}", "\u{378}"]), ("\u{11a8}\u{20}",
+ &["\u{11a8}", "\u{20}"]), ("\u{11a8}\u{308}\u{20}", &["\u{11a8}\u{308}", "\u{20}"]),
+ ("\u{11a8}\u{d}", &["\u{11a8}", "\u{d}"]), ("\u{11a8}\u{308}\u{d}", &["\u{11a8}\u{308}",
+ "\u{d}"]), ("\u{11a8}\u{a}", &["\u{11a8}", "\u{a}"]), ("\u{11a8}\u{308}\u{a}",
+ &["\u{11a8}\u{308}", "\u{a}"]), ("\u{11a8}\u{1}", &["\u{11a8}", "\u{1}"]),
+ ("\u{11a8}\u{308}\u{1}", &["\u{11a8}\u{308}", "\u{1}"]), ("\u{11a8}\u{34f}",
+ &["\u{11a8}\u{34f}"]), ("\u{11a8}\u{308}\u{34f}", &["\u{11a8}\u{308}\u{34f}"]),
+ ("\u{11a8}\u{1f1e6}", &["\u{11a8}", "\u{1f1e6}"]), ("\u{11a8}\u{308}\u{1f1e6}",
+ &["\u{11a8}\u{308}", "\u{1f1e6}"]), ("\u{11a8}\u{600}", &["\u{11a8}", "\u{600}"]),
+ ("\u{11a8}\u{308}\u{600}", &["\u{11a8}\u{308}", "\u{600}"]), ("\u{11a8}\u{1100}",
+ &["\u{11a8}", "\u{1100}"]), ("\u{11a8}\u{308}\u{1100}", &["\u{11a8}\u{308}", "\u{1100}"]),
+ ("\u{11a8}\u{1160}", &["\u{11a8}", "\u{1160}"]), ("\u{11a8}\u{308}\u{1160}",
+ &["\u{11a8}\u{308}", "\u{1160}"]), ("\u{11a8}\u{11a8}", &["\u{11a8}\u{11a8}"]),
+ ("\u{11a8}\u{308}\u{11a8}", &["\u{11a8}\u{308}", "\u{11a8}"]), ("\u{11a8}\u{ac00}",
+ &["\u{11a8}", "\u{ac00}"]), ("\u{11a8}\u{308}\u{ac00}", &["\u{11a8}\u{308}", "\u{ac00}"]),
+ ("\u{11a8}\u{ac01}", &["\u{11a8}", "\u{ac01}"]), ("\u{11a8}\u{308}\u{ac01}",
+ &["\u{11a8}\u{308}", "\u{ac01}"]), ("\u{11a8}\u{231a}", &["\u{11a8}", "\u{231a}"]),
+ ("\u{11a8}\u{308}\u{231a}", &["\u{11a8}\u{308}", "\u{231a}"]), ("\u{11a8}\u{300}",
+ &["\u{11a8}\u{300}"]), ("\u{11a8}\u{308}\u{300}", &["\u{11a8}\u{308}\u{300}"]),
+ ("\u{11a8}\u{200d}", &["\u{11a8}\u{200d}"]), ("\u{11a8}\u{308}\u{200d}",
+ &["\u{11a8}\u{308}\u{200d}"]), ("\u{11a8}\u{378}", &["\u{11a8}", "\u{378}"]),
+ ("\u{11a8}\u{308}\u{378}", &["\u{11a8}\u{308}", "\u{378}"]), ("\u{ac00}\u{20}",
+ &["\u{ac00}", "\u{20}"]), ("\u{ac00}\u{308}\u{20}", &["\u{ac00}\u{308}", "\u{20}"]),
+ ("\u{ac00}\u{d}", &["\u{ac00}", "\u{d}"]), ("\u{ac00}\u{308}\u{d}", &["\u{ac00}\u{308}",
+ "\u{d}"]), ("\u{ac00}\u{a}", &["\u{ac00}", "\u{a}"]), ("\u{ac00}\u{308}\u{a}",
+ &["\u{ac00}\u{308}", "\u{a}"]), ("\u{ac00}\u{1}", &["\u{ac00}", "\u{1}"]),
+ ("\u{ac00}\u{308}\u{1}", &["\u{ac00}\u{308}", "\u{1}"]), ("\u{ac00}\u{34f}",
+ &["\u{ac00}\u{34f}"]), ("\u{ac00}\u{308}\u{34f}", &["\u{ac00}\u{308}\u{34f}"]),
+ ("\u{ac00}\u{1f1e6}", &["\u{ac00}", "\u{1f1e6}"]), ("\u{ac00}\u{308}\u{1f1e6}",
+ &["\u{ac00}\u{308}", "\u{1f1e6}"]), ("\u{ac00}\u{600}", &["\u{ac00}", "\u{600}"]),
+ ("\u{ac00}\u{308}\u{600}", &["\u{ac00}\u{308}", "\u{600}"]), ("\u{ac00}\u{1100}",
+ &["\u{ac00}", "\u{1100}"]), ("\u{ac00}\u{308}\u{1100}", &["\u{ac00}\u{308}", "\u{1100}"]),
+ ("\u{ac00}\u{1160}", &["\u{ac00}\u{1160}"]), ("\u{ac00}\u{308}\u{1160}",
+ &["\u{ac00}\u{308}", "\u{1160}"]), ("\u{ac00}\u{11a8}", &["\u{ac00}\u{11a8}"]),
+ ("\u{ac00}\u{308}\u{11a8}", &["\u{ac00}\u{308}", "\u{11a8}"]), ("\u{ac00}\u{ac00}",
+ &["\u{ac00}", "\u{ac00}"]), ("\u{ac00}\u{308}\u{ac00}", &["\u{ac00}\u{308}", "\u{ac00}"]),
+ ("\u{ac00}\u{ac01}", &["\u{ac00}", "\u{ac01}"]), ("\u{ac00}\u{308}\u{ac01}",
+ &["\u{ac00}\u{308}", "\u{ac01}"]), ("\u{ac00}\u{231a}", &["\u{ac00}", "\u{231a}"]),
+ ("\u{ac00}\u{308}\u{231a}", &["\u{ac00}\u{308}", "\u{231a}"]), ("\u{ac00}\u{300}",
+ &["\u{ac00}\u{300}"]), ("\u{ac00}\u{308}\u{300}", &["\u{ac00}\u{308}\u{300}"]),
+ ("\u{ac00}\u{200d}", &["\u{ac00}\u{200d}"]), ("\u{ac00}\u{308}\u{200d}",
+ &["\u{ac00}\u{308}\u{200d}"]), ("\u{ac00}\u{378}", &["\u{ac00}", "\u{378}"]),
+ ("\u{ac00}\u{308}\u{378}", &["\u{ac00}\u{308}", "\u{378}"]), ("\u{ac01}\u{20}",
+ &["\u{ac01}", "\u{20}"]), ("\u{ac01}\u{308}\u{20}", &["\u{ac01}\u{308}", "\u{20}"]),
+ ("\u{ac01}\u{d}", &["\u{ac01}", "\u{d}"]), ("\u{ac01}\u{308}\u{d}", &["\u{ac01}\u{308}",
+ "\u{d}"]), ("\u{ac01}\u{a}", &["\u{ac01}", "\u{a}"]), ("\u{ac01}\u{308}\u{a}",
+ &["\u{ac01}\u{308}", "\u{a}"]), ("\u{ac01}\u{1}", &["\u{ac01}", "\u{1}"]),
+ ("\u{ac01}\u{308}\u{1}", &["\u{ac01}\u{308}", "\u{1}"]), ("\u{ac01}\u{34f}",
+ &["\u{ac01}\u{34f}"]), ("\u{ac01}\u{308}\u{34f}", &["\u{ac01}\u{308}\u{34f}"]),
+ ("\u{ac01}\u{1f1e6}", &["\u{ac01}", "\u{1f1e6}"]), ("\u{ac01}\u{308}\u{1f1e6}",
+ &["\u{ac01}\u{308}", "\u{1f1e6}"]), ("\u{ac01}\u{600}", &["\u{ac01}", "\u{600}"]),
+ ("\u{ac01}\u{308}\u{600}", &["\u{ac01}\u{308}", "\u{600}"]), ("\u{ac01}\u{1100}",
+ &["\u{ac01}", "\u{1100}"]), ("\u{ac01}\u{308}\u{1100}", &["\u{ac01}\u{308}", "\u{1100}"]),
+ ("\u{ac01}\u{1160}", &["\u{ac01}", "\u{1160}"]), ("\u{ac01}\u{308}\u{1160}",
+ &["\u{ac01}\u{308}", "\u{1160}"]), ("\u{ac01}\u{11a8}", &["\u{ac01}\u{11a8}"]),
+ ("\u{ac01}\u{308}\u{11a8}", &["\u{ac01}\u{308}", "\u{11a8}"]), ("\u{ac01}\u{ac00}",
+ &["\u{ac01}", "\u{ac00}"]), ("\u{ac01}\u{308}\u{ac00}", &["\u{ac01}\u{308}", "\u{ac00}"]),
+ ("\u{ac01}\u{ac01}", &["\u{ac01}", "\u{ac01}"]), ("\u{ac01}\u{308}\u{ac01}",
+ &["\u{ac01}\u{308}", "\u{ac01}"]), ("\u{ac01}\u{231a}", &["\u{ac01}", "\u{231a}"]),
+ ("\u{ac01}\u{308}\u{231a}", &["\u{ac01}\u{308}", "\u{231a}"]), ("\u{ac01}\u{300}",
+ &["\u{ac01}\u{300}"]), ("\u{ac01}\u{308}\u{300}", &["\u{ac01}\u{308}\u{300}"]),
+ ("\u{ac01}\u{200d}", &["\u{ac01}\u{200d}"]), ("\u{ac01}\u{308}\u{200d}",
+ &["\u{ac01}\u{308}\u{200d}"]), ("\u{ac01}\u{378}", &["\u{ac01}", "\u{378}"]),
+ ("\u{ac01}\u{308}\u{378}", &["\u{ac01}\u{308}", "\u{378}"]), ("\u{231a}\u{20}",
+ &["\u{231a}", "\u{20}"]), ("\u{231a}\u{308}\u{20}", &["\u{231a}\u{308}", "\u{20}"]),
+ ("\u{231a}\u{d}", &["\u{231a}", "\u{d}"]), ("\u{231a}\u{308}\u{d}", &["\u{231a}\u{308}",
+ "\u{d}"]), ("\u{231a}\u{a}", &["\u{231a}", "\u{a}"]), ("\u{231a}\u{308}\u{a}",
+ &["\u{231a}\u{308}", "\u{a}"]), ("\u{231a}\u{1}", &["\u{231a}", "\u{1}"]),
+ ("\u{231a}\u{308}\u{1}", &["\u{231a}\u{308}", "\u{1}"]), ("\u{231a}\u{34f}",
+ &["\u{231a}\u{34f}"]), ("\u{231a}\u{308}\u{34f}", &["\u{231a}\u{308}\u{34f}"]),
+ ("\u{231a}\u{1f1e6}", &["\u{231a}", "\u{1f1e6}"]), ("\u{231a}\u{308}\u{1f1e6}",
+ &["\u{231a}\u{308}", "\u{1f1e6}"]), ("\u{231a}\u{600}", &["\u{231a}", "\u{600}"]),
+ ("\u{231a}\u{308}\u{600}", &["\u{231a}\u{308}", "\u{600}"]), ("\u{231a}\u{1100}",
+ &["\u{231a}", "\u{1100}"]), ("\u{231a}\u{308}\u{1100}", &["\u{231a}\u{308}", "\u{1100}"]),
+ ("\u{231a}\u{1160}", &["\u{231a}", "\u{1160}"]), ("\u{231a}\u{308}\u{1160}",
+ &["\u{231a}\u{308}", "\u{1160}"]), ("\u{231a}\u{11a8}", &["\u{231a}", "\u{11a8}"]),
+ ("\u{231a}\u{308}\u{11a8}", &["\u{231a}\u{308}", "\u{11a8}"]), ("\u{231a}\u{ac00}",
+ &["\u{231a}", "\u{ac00}"]), ("\u{231a}\u{308}\u{ac00}", &["\u{231a}\u{308}", "\u{ac00}"]),
+ ("\u{231a}\u{ac01}", &["\u{231a}", "\u{ac01}"]), ("\u{231a}\u{308}\u{ac01}",
+ &["\u{231a}\u{308}", "\u{ac01}"]), ("\u{231a}\u{231a}", &["\u{231a}", "\u{231a}"]),
+ ("\u{231a}\u{308}\u{231a}", &["\u{231a}\u{308}", "\u{231a}"]), ("\u{231a}\u{300}",
+ &["\u{231a}\u{300}"]), ("\u{231a}\u{308}\u{300}", &["\u{231a}\u{308}\u{300}"]),
+ ("\u{231a}\u{200d}", &["\u{231a}\u{200d}"]), ("\u{231a}\u{308}\u{200d}",
+ &["\u{231a}\u{308}\u{200d}"]), ("\u{231a}\u{378}", &["\u{231a}", "\u{378}"]),
+ ("\u{231a}\u{308}\u{378}", &["\u{231a}\u{308}", "\u{378}"]), ("\u{300}\u{20}", &["\u{300}",
+ "\u{20}"]), ("\u{300}\u{308}\u{20}", &["\u{300}\u{308}", "\u{20}"]), ("\u{300}\u{d}",
+ &["\u{300}", "\u{d}"]), ("\u{300}\u{308}\u{d}", &["\u{300}\u{308}", "\u{d}"]),
+ ("\u{300}\u{a}", &["\u{300}", "\u{a}"]), ("\u{300}\u{308}\u{a}", &["\u{300}\u{308}",
+ "\u{a}"]), ("\u{300}\u{1}", &["\u{300}", "\u{1}"]), ("\u{300}\u{308}\u{1}",
+ &["\u{300}\u{308}", "\u{1}"]), ("\u{300}\u{34f}", &["\u{300}\u{34f}"]),
+ ("\u{300}\u{308}\u{34f}", &["\u{300}\u{308}\u{34f}"]), ("\u{300}\u{1f1e6}", &["\u{300}",
+ "\u{1f1e6}"]), ("\u{300}\u{308}\u{1f1e6}", &["\u{300}\u{308}", "\u{1f1e6}"]),
+ ("\u{300}\u{600}", &["\u{300}", "\u{600}"]), ("\u{300}\u{308}\u{600}", &["\u{300}\u{308}",
+ "\u{600}"]), ("\u{300}\u{1100}", &["\u{300}", "\u{1100}"]), ("\u{300}\u{308}\u{1100}",
+ &["\u{300}\u{308}", "\u{1100}"]), ("\u{300}\u{1160}", &["\u{300}", "\u{1160}"]),
+ ("\u{300}\u{308}\u{1160}", &["\u{300}\u{308}", "\u{1160}"]), ("\u{300}\u{11a8}",
+ &["\u{300}", "\u{11a8}"]), ("\u{300}\u{308}\u{11a8}", &["\u{300}\u{308}", "\u{11a8}"]),
+ ("\u{300}\u{ac00}", &["\u{300}", "\u{ac00}"]), ("\u{300}\u{308}\u{ac00}",
+ &["\u{300}\u{308}", "\u{ac00}"]), ("\u{300}\u{ac01}", &["\u{300}", "\u{ac01}"]),
+ ("\u{300}\u{308}\u{ac01}", &["\u{300}\u{308}", "\u{ac01}"]), ("\u{300}\u{231a}",
+ &["\u{300}", "\u{231a}"]), ("\u{300}\u{308}\u{231a}", &["\u{300}\u{308}", "\u{231a}"]),
+ ("\u{300}\u{300}", &["\u{300}\u{300}"]), ("\u{300}\u{308}\u{300}",
+ &["\u{300}\u{308}\u{300}"]), ("\u{300}\u{200d}", &["\u{300}\u{200d}"]),
+ ("\u{300}\u{308}\u{200d}", &["\u{300}\u{308}\u{200d}"]), ("\u{300}\u{378}", &["\u{300}",
+ "\u{378}"]), ("\u{300}\u{308}\u{378}", &["\u{300}\u{308}", "\u{378}"]), ("\u{200d}\u{20}",
+ &["\u{200d}", "\u{20}"]), ("\u{200d}\u{308}\u{20}", &["\u{200d}\u{308}", "\u{20}"]),
+ ("\u{200d}\u{d}", &["\u{200d}", "\u{d}"]), ("\u{200d}\u{308}\u{d}", &["\u{200d}\u{308}",
+ "\u{d}"]), ("\u{200d}\u{a}", &["\u{200d}", "\u{a}"]), ("\u{200d}\u{308}\u{a}",
+ &["\u{200d}\u{308}", "\u{a}"]), ("\u{200d}\u{1}", &["\u{200d}", "\u{1}"]),
+ ("\u{200d}\u{308}\u{1}", &["\u{200d}\u{308}", "\u{1}"]), ("\u{200d}\u{34f}",
+ &["\u{200d}\u{34f}"]), ("\u{200d}\u{308}\u{34f}", &["\u{200d}\u{308}\u{34f}"]),
+ ("\u{200d}\u{1f1e6}", &["\u{200d}", "\u{1f1e6}"]), ("\u{200d}\u{308}\u{1f1e6}",
+ &["\u{200d}\u{308}", "\u{1f1e6}"]), ("\u{200d}\u{600}", &["\u{200d}", "\u{600}"]),
+ ("\u{200d}\u{308}\u{600}", &["\u{200d}\u{308}", "\u{600}"]), ("\u{200d}\u{1100}",
+ &["\u{200d}", "\u{1100}"]), ("\u{200d}\u{308}\u{1100}", &["\u{200d}\u{308}", "\u{1100}"]),
+ ("\u{200d}\u{1160}", &["\u{200d}", "\u{1160}"]), ("\u{200d}\u{308}\u{1160}",
+ &["\u{200d}\u{308}", "\u{1160}"]), ("\u{200d}\u{11a8}", &["\u{200d}", "\u{11a8}"]),
+ ("\u{200d}\u{308}\u{11a8}", &["\u{200d}\u{308}", "\u{11a8}"]), ("\u{200d}\u{ac00}",
+ &["\u{200d}", "\u{ac00}"]), ("\u{200d}\u{308}\u{ac00}", &["\u{200d}\u{308}", "\u{ac00}"]),
+ ("\u{200d}\u{ac01}", &["\u{200d}", "\u{ac01}"]), ("\u{200d}\u{308}\u{ac01}",
+ &["\u{200d}\u{308}", "\u{ac01}"]), ("\u{200d}\u{231a}", &["\u{200d}", "\u{231a}"]),
+ ("\u{200d}\u{308}\u{231a}", &["\u{200d}\u{308}", "\u{231a}"]), ("\u{200d}\u{300}",
+ &["\u{200d}\u{300}"]), ("\u{200d}\u{308}\u{300}", &["\u{200d}\u{308}\u{300}"]),
+ ("\u{200d}\u{200d}", &["\u{200d}\u{200d}"]), ("\u{200d}\u{308}\u{200d}",
+ &["\u{200d}\u{308}\u{200d}"]), ("\u{200d}\u{378}", &["\u{200d}", "\u{378}"]),
+ ("\u{200d}\u{308}\u{378}", &["\u{200d}\u{308}", "\u{378}"]), ("\u{378}\u{20}", &["\u{378}",
+ "\u{20}"]), ("\u{378}\u{308}\u{20}", &["\u{378}\u{308}", "\u{20}"]), ("\u{378}\u{d}",
+ &["\u{378}", "\u{d}"]), ("\u{378}\u{308}\u{d}", &["\u{378}\u{308}", "\u{d}"]),
+ ("\u{378}\u{a}", &["\u{378}", "\u{a}"]), ("\u{378}\u{308}\u{a}", &["\u{378}\u{308}",
+ "\u{a}"]), ("\u{378}\u{1}", &["\u{378}", "\u{1}"]), ("\u{378}\u{308}\u{1}",
+ &["\u{378}\u{308}", "\u{1}"]), ("\u{378}\u{34f}", &["\u{378}\u{34f}"]),
+ ("\u{378}\u{308}\u{34f}", &["\u{378}\u{308}\u{34f}"]), ("\u{378}\u{1f1e6}", &["\u{378}",
+ "\u{1f1e6}"]), ("\u{378}\u{308}\u{1f1e6}", &["\u{378}\u{308}", "\u{1f1e6}"]),
+ ("\u{378}\u{600}", &["\u{378}", "\u{600}"]), ("\u{378}\u{308}\u{600}", &["\u{378}\u{308}",
+ "\u{600}"]), ("\u{378}\u{1100}", &["\u{378}", "\u{1100}"]), ("\u{378}\u{308}\u{1100}",
+ &["\u{378}\u{308}", "\u{1100}"]), ("\u{378}\u{1160}", &["\u{378}", "\u{1160}"]),
+ ("\u{378}\u{308}\u{1160}", &["\u{378}\u{308}", "\u{1160}"]), ("\u{378}\u{11a8}",
+ &["\u{378}", "\u{11a8}"]), ("\u{378}\u{308}\u{11a8}", &["\u{378}\u{308}", "\u{11a8}"]),
+ ("\u{378}\u{ac00}", &["\u{378}", "\u{ac00}"]), ("\u{378}\u{308}\u{ac00}",
+ &["\u{378}\u{308}", "\u{ac00}"]), ("\u{378}\u{ac01}", &["\u{378}", "\u{ac01}"]),
+ ("\u{378}\u{308}\u{ac01}", &["\u{378}\u{308}", "\u{ac01}"]), ("\u{378}\u{231a}",
+ &["\u{378}", "\u{231a}"]), ("\u{378}\u{308}\u{231a}", &["\u{378}\u{308}", "\u{231a}"]),
+ ("\u{378}\u{300}", &["\u{378}\u{300}"]), ("\u{378}\u{308}\u{300}",
+ &["\u{378}\u{308}\u{300}"]), ("\u{378}\u{200d}", &["\u{378}\u{200d}"]),
+ ("\u{378}\u{308}\u{200d}", &["\u{378}\u{308}\u{200d}"]), ("\u{378}\u{378}", &["\u{378}",
+ "\u{378}"]), ("\u{378}\u{308}\u{378}", &["\u{378}\u{308}", "\u{378}"]),
+ ("\u{d}\u{a}\u{61}\u{a}\u{308}", &["\u{d}\u{a}", "\u{61}", "\u{a}", "\u{308}"]),
+ ("\u{61}\u{308}", &["\u{61}\u{308}"]), ("\u{20}\u{200d}\u{646}", &["\u{20}\u{200d}",
+ "\u{646}"]), ("\u{646}\u{200d}\u{20}", &["\u{646}\u{200d}", "\u{20}"]), ("\u{1100}\u{1100}",
+ &["\u{1100}\u{1100}"]), ("\u{ac00}\u{11a8}\u{1100}", &["\u{ac00}\u{11a8}", "\u{1100}"]),
+ ("\u{ac01}\u{11a8}\u{1100}", &["\u{ac01}\u{11a8}", "\u{1100}"]),
+ ("\u{1f1e6}\u{1f1e7}\u{1f1e8}\u{62}", &["\u{1f1e6}\u{1f1e7}", "\u{1f1e8}", "\u{62}"]),
+ ("\u{61}\u{1f1e6}\u{1f1e7}\u{1f1e8}\u{62}", &["\u{61}", "\u{1f1e6}\u{1f1e7}", "\u{1f1e8}",
+ "\u{62}"]), ("\u{61}\u{1f1e6}\u{1f1e7}\u{200d}\u{1f1e8}\u{62}", &["\u{61}",
+ "\u{1f1e6}\u{1f1e7}\u{200d}", "\u{1f1e8}", "\u{62}"]),
+ ("\u{61}\u{1f1e6}\u{200d}\u{1f1e7}\u{1f1e8}\u{62}", &["\u{61}", "\u{1f1e6}\u{200d}",
+ "\u{1f1e7}\u{1f1e8}", "\u{62}"]), ("\u{61}\u{1f1e6}\u{1f1e7}\u{1f1e8}\u{1f1e9}\u{62}",
+ &["\u{61}", "\u{1f1e6}\u{1f1e7}", "\u{1f1e8}\u{1f1e9}", "\u{62}"]), ("\u{61}\u{200d}",
+ &["\u{61}\u{200d}"]), ("\u{61}\u{308}\u{62}", &["\u{61}\u{308}", "\u{62}"]),
+ ("\u{1f476}\u{1f3ff}\u{1f476}", &["\u{1f476}\u{1f3ff}", "\u{1f476}"]),
+ ("\u{61}\u{1f3ff}\u{1f476}", &["\u{61}\u{1f3ff}", "\u{1f476}"]),
+ ("\u{61}\u{1f3ff}\u{1f476}\u{200d}\u{1f6d1}", &["\u{61}\u{1f3ff}",
+ "\u{1f476}\u{200d}\u{1f6d1}"]), ("\u{1f476}\u{1f3ff}\u{308}\u{200d}\u{1f476}\u{1f3ff}",
+ &["\u{1f476}\u{1f3ff}\u{308}\u{200d}\u{1f476}\u{1f3ff}"]), ("\u{1f6d1}\u{200d}\u{1f6d1}",
+ &["\u{1f6d1}\u{200d}\u{1f6d1}"]), ("\u{61}\u{200d}\u{1f6d1}", &["\u{61}\u{200d}",
+ "\u{1f6d1}"]), ("\u{2701}\u{200d}\u{2701}", &["\u{2701}\u{200d}\u{2701}"]),
+ ("\u{61}\u{200d}\u{2701}", &["\u{61}\u{200d}", "\u{2701}"])
+ ];
+
+ pub const TEST_DIFF: &'static [(&'static str, &'static [&'static str], &'static [&'static str])] = &[
+ ("\u{20}\u{903}", &["\u{20}\u{903}"], &["\u{20}", "\u{903}"]), ("\u{20}\u{308}\u{903}",
+ &["\u{20}\u{308}\u{903}"], &["\u{20}\u{308}", "\u{903}"]), ("\u{d}\u{308}\u{903}",
+ &["\u{d}", "\u{308}\u{903}"], &["\u{d}", "\u{308}", "\u{903}"]), ("\u{a}\u{308}\u{903}",
+ &["\u{a}", "\u{308}\u{903}"], &["\u{a}", "\u{308}", "\u{903}"]), ("\u{1}\u{308}\u{903}",
+ &["\u{1}", "\u{308}\u{903}"], &["\u{1}", "\u{308}", "\u{903}"]), ("\u{34f}\u{903}",
+ &["\u{34f}\u{903}"], &["\u{34f}", "\u{903}"]), ("\u{34f}\u{308}\u{903}",
+ &["\u{34f}\u{308}\u{903}"], &["\u{34f}\u{308}", "\u{903}"]), ("\u{1f1e6}\u{903}",
+ &["\u{1f1e6}\u{903}"], &["\u{1f1e6}", "\u{903}"]), ("\u{1f1e6}\u{308}\u{903}",
+ &["\u{1f1e6}\u{308}\u{903}"], &["\u{1f1e6}\u{308}", "\u{903}"]), ("\u{600}\u{20}",
+ &["\u{600}\u{20}"], &["\u{600}", "\u{20}"]), ("\u{600}\u{1f1e6}", &["\u{600}\u{1f1e6}"],
+ &["\u{600}", "\u{1f1e6}"]), ("\u{600}\u{600}", &["\u{600}\u{600}"], &["\u{600}",
+ "\u{600}"]), ("\u{600}\u{903}", &["\u{600}\u{903}"], &["\u{600}", "\u{903}"]),
+ ("\u{600}\u{308}\u{903}", &["\u{600}\u{308}\u{903}"], &["\u{600}\u{308}", "\u{903}"]),
+ ("\u{600}\u{1100}", &["\u{600}\u{1100}"], &["\u{600}", "\u{1100}"]), ("\u{600}\u{1160}",
+ &["\u{600}\u{1160}"], &["\u{600}", "\u{1160}"]), ("\u{600}\u{11a8}", &["\u{600}\u{11a8}"],
+ &["\u{600}", "\u{11a8}"]), ("\u{600}\u{ac00}", &["\u{600}\u{ac00}"], &["\u{600}",
+ "\u{ac00}"]), ("\u{600}\u{ac01}", &["\u{600}\u{ac01}"], &["\u{600}", "\u{ac01}"]),
+ ("\u{600}\u{231a}", &["\u{600}\u{231a}"], &["\u{600}", "\u{231a}"]), ("\u{600}\u{378}",
+ &["\u{600}\u{378}"], &["\u{600}", "\u{378}"]), ("\u{903}\u{903}", &["\u{903}\u{903}"],
+ &["\u{903}", "\u{903}"]), ("\u{903}\u{308}\u{903}", &["\u{903}\u{308}\u{903}"],
+ &["\u{903}\u{308}", "\u{903}"]), ("\u{1100}\u{903}", &["\u{1100}\u{903}"], &["\u{1100}",
+ "\u{903}"]), ("\u{1100}\u{308}\u{903}", &["\u{1100}\u{308}\u{903}"], &["\u{1100}\u{308}",
+ "\u{903}"]), ("\u{1160}\u{903}", &["\u{1160}\u{903}"], &["\u{1160}", "\u{903}"]),
+ ("\u{1160}\u{308}\u{903}", &["\u{1160}\u{308}\u{903}"], &["\u{1160}\u{308}", "\u{903}"]),
+ ("\u{11a8}\u{903}", &["\u{11a8}\u{903}"], &["\u{11a8}", "\u{903}"]),
+ ("\u{11a8}\u{308}\u{903}", &["\u{11a8}\u{308}\u{903}"], &["\u{11a8}\u{308}", "\u{903}"]),
+ ("\u{ac00}\u{903}", &["\u{ac00}\u{903}"], &["\u{ac00}", "\u{903}"]),
+ ("\u{ac00}\u{308}\u{903}", &["\u{ac00}\u{308}\u{903}"], &["\u{ac00}\u{308}", "\u{903}"]),
+ ("\u{ac01}\u{903}", &["\u{ac01}\u{903}"], &["\u{ac01}", "\u{903}"]),
+ ("\u{ac01}\u{308}\u{903}", &["\u{ac01}\u{308}\u{903}"], &["\u{ac01}\u{308}", "\u{903}"]),
+ ("\u{231a}\u{903}", &["\u{231a}\u{903}"], &["\u{231a}", "\u{903}"]),
+ ("\u{231a}\u{308}\u{903}", &["\u{231a}\u{308}\u{903}"], &["\u{231a}\u{308}", "\u{903}"]),
+ ("\u{300}\u{903}", &["\u{300}\u{903}"], &["\u{300}", "\u{903}"]), ("\u{300}\u{308}\u{903}",
+ &["\u{300}\u{308}\u{903}"], &["\u{300}\u{308}", "\u{903}"]), ("\u{200d}\u{903}",
+ &["\u{200d}\u{903}"], &["\u{200d}", "\u{903}"]), ("\u{200d}\u{308}\u{903}",
+ &["\u{200d}\u{308}\u{903}"], &["\u{200d}\u{308}", "\u{903}"]), ("\u{378}\u{903}",
+ &["\u{378}\u{903}"], &["\u{378}", "\u{903}"]), ("\u{378}\u{308}\u{903}",
+ &["\u{378}\u{308}\u{903}"], &["\u{378}\u{308}", "\u{903}"]), ("\u{61}\u{903}\u{62}",
+ &["\u{61}\u{903}", "\u{62}"], &["\u{61}", "\u{903}", "\u{62}"]), ("\u{61}\u{600}\u{62}",
+ &["\u{61}", "\u{600}\u{62}"], &["\u{61}", "\u{600}", "\u{62}"])
+ ];
+
+ // official Unicode test data
+ // http://www.unicode.org/Public/12.0.0/ucd/auxiliary/WordBreakTest.txt
+ pub const TEST_WORD: &'static [(&'static str, &'static [&'static str])] = &[
+ ("\u{1}\u{1}", &["\u{1}", "\u{1}"]), ("\u{1}\u{308}\u{1}", &["\u{1}\u{308}", "\u{1}"]),
+ ("\u{1}\u{d}", &["\u{1}", "\u{d}"]), ("\u{1}\u{308}\u{d}", &["\u{1}\u{308}", "\u{d}"]),
+ ("\u{1}\u{a}", &["\u{1}", "\u{a}"]), ("\u{1}\u{308}\u{a}", &["\u{1}\u{308}", "\u{a}"]),
+ ("\u{1}\u{b}", &["\u{1}", "\u{b}"]), ("\u{1}\u{308}\u{b}", &["\u{1}\u{308}", "\u{b}"]),
+ ("\u{1}\u{3031}", &["\u{1}", "\u{3031}"]), ("\u{1}\u{308}\u{3031}", &["\u{1}\u{308}",
+ "\u{3031}"]), ("\u{1}\u{41}", &["\u{1}", "\u{41}"]), ("\u{1}\u{308}\u{41}",
+ &["\u{1}\u{308}", "\u{41}"]), ("\u{1}\u{3a}", &["\u{1}", "\u{3a}"]), ("\u{1}\u{308}\u{3a}",
+ &["\u{1}\u{308}", "\u{3a}"]), ("\u{1}\u{2c}", &["\u{1}", "\u{2c}"]), ("\u{1}\u{308}\u{2c}",
+ &["\u{1}\u{308}", "\u{2c}"]), ("\u{1}\u{2e}", &["\u{1}", "\u{2e}"]), ("\u{1}\u{308}\u{2e}",
+ &["\u{1}\u{308}", "\u{2e}"]), ("\u{1}\u{30}", &["\u{1}", "\u{30}"]), ("\u{1}\u{308}\u{30}",
+ &["\u{1}\u{308}", "\u{30}"]), ("\u{1}\u{5f}", &["\u{1}", "\u{5f}"]), ("\u{1}\u{308}\u{5f}",
+ &["\u{1}\u{308}", "\u{5f}"]), ("\u{1}\u{1f1e6}", &["\u{1}", "\u{1f1e6}"]),
+ ("\u{1}\u{308}\u{1f1e6}", &["\u{1}\u{308}", "\u{1f1e6}"]), ("\u{1}\u{5d0}", &["\u{1}",
+ "\u{5d0}"]), ("\u{1}\u{308}\u{5d0}", &["\u{1}\u{308}", "\u{5d0}"]), ("\u{1}\u{22}",
+ &["\u{1}", "\u{22}"]), ("\u{1}\u{308}\u{22}", &["\u{1}\u{308}", "\u{22}"]), ("\u{1}\u{27}",
+ &["\u{1}", "\u{27}"]), ("\u{1}\u{308}\u{27}", &["\u{1}\u{308}", "\u{27}"]),
+ ("\u{1}\u{231a}", &["\u{1}", "\u{231a}"]), ("\u{1}\u{308}\u{231a}", &["\u{1}\u{308}",
+ "\u{231a}"]), ("\u{1}\u{20}", &["\u{1}", "\u{20}"]), ("\u{1}\u{308}\u{20}",
+ &["\u{1}\u{308}", "\u{20}"]), ("\u{1}\u{ad}", &["\u{1}\u{ad}"]), ("\u{1}\u{308}\u{ad}",
+ &["\u{1}\u{308}\u{ad}"]), ("\u{1}\u{300}", &["\u{1}\u{300}"]), ("\u{1}\u{308}\u{300}",
+ &["\u{1}\u{308}\u{300}"]), ("\u{1}\u{200d}", &["\u{1}\u{200d}"]), ("\u{1}\u{308}\u{200d}",
+ &["\u{1}\u{308}\u{200d}"]), ("\u{1}\u{61}\u{2060}", &["\u{1}", "\u{61}\u{2060}"]),
+ ("\u{1}\u{308}\u{61}\u{2060}", &["\u{1}\u{308}", "\u{61}\u{2060}"]), ("\u{1}\u{61}\u{3a}",
+ &["\u{1}", "\u{61}", "\u{3a}"]), ("\u{1}\u{308}\u{61}\u{3a}", &["\u{1}\u{308}", "\u{61}",
+ "\u{3a}"]), ("\u{1}\u{61}\u{27}", &["\u{1}", "\u{61}", "\u{27}"]),
+ ("\u{1}\u{308}\u{61}\u{27}", &["\u{1}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{1}\u{61}\u{27}\u{2060}", &["\u{1}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{1}\u{308}\u{61}\u{27}\u{2060}", &["\u{1}\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{1}\u{61}\u{2c}", &["\u{1}", "\u{61}", "\u{2c}"]), ("\u{1}\u{308}\u{61}\u{2c}",
+ &["\u{1}\u{308}", "\u{61}", "\u{2c}"]), ("\u{1}\u{31}\u{3a}", &["\u{1}", "\u{31}",
+ "\u{3a}"]), ("\u{1}\u{308}\u{31}\u{3a}", &["\u{1}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{1}\u{31}\u{27}", &["\u{1}", "\u{31}", "\u{27}"]), ("\u{1}\u{308}\u{31}\u{27}",
+ &["\u{1}\u{308}", "\u{31}", "\u{27}"]), ("\u{1}\u{31}\u{2c}", &["\u{1}", "\u{31}",
+ "\u{2c}"]), ("\u{1}\u{308}\u{31}\u{2c}", &["\u{1}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{1}\u{31}\u{2e}\u{2060}", &["\u{1}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{1}\u{308}\u{31}\u{2e}\u{2060}", &["\u{1}\u{308}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{d}\u{1}", &["\u{d}", "\u{1}"]), ("\u{d}\u{308}\u{1}", &["\u{d}", "\u{308}", "\u{1}"]),
+ ("\u{d}\u{d}", &["\u{d}", "\u{d}"]), ("\u{d}\u{308}\u{d}", &["\u{d}", "\u{308}", "\u{d}"]),
+ ("\u{d}\u{a}", &["\u{d}\u{a}"]), ("\u{d}\u{308}\u{a}", &["\u{d}", "\u{308}", "\u{a}"]),
+ ("\u{d}\u{b}", &["\u{d}", "\u{b}"]), ("\u{d}\u{308}\u{b}", &["\u{d}", "\u{308}", "\u{b}"]),
+ ("\u{d}\u{3031}", &["\u{d}", "\u{3031}"]), ("\u{d}\u{308}\u{3031}", &["\u{d}", "\u{308}",
+ "\u{3031}"]), ("\u{d}\u{41}", &["\u{d}", "\u{41}"]), ("\u{d}\u{308}\u{41}", &["\u{d}",
+ "\u{308}", "\u{41}"]), ("\u{d}\u{3a}", &["\u{d}", "\u{3a}"]), ("\u{d}\u{308}\u{3a}",
+ &["\u{d}", "\u{308}", "\u{3a}"]), ("\u{d}\u{2c}", &["\u{d}", "\u{2c}"]),
+ ("\u{d}\u{308}\u{2c}", &["\u{d}", "\u{308}", "\u{2c}"]), ("\u{d}\u{2e}", &["\u{d}",
+ "\u{2e}"]), ("\u{d}\u{308}\u{2e}", &["\u{d}", "\u{308}", "\u{2e}"]), ("\u{d}\u{30}",
+ &["\u{d}", "\u{30}"]), ("\u{d}\u{308}\u{30}", &["\u{d}", "\u{308}", "\u{30}"]),
+ ("\u{d}\u{5f}", &["\u{d}", "\u{5f}"]), ("\u{d}\u{308}\u{5f}", &["\u{d}", "\u{308}",
+ "\u{5f}"]), ("\u{d}\u{1f1e6}", &["\u{d}", "\u{1f1e6}"]), ("\u{d}\u{308}\u{1f1e6}",
+ &["\u{d}", "\u{308}", "\u{1f1e6}"]), ("\u{d}\u{5d0}", &["\u{d}", "\u{5d0}"]),
+ ("\u{d}\u{308}\u{5d0}", &["\u{d}", "\u{308}", "\u{5d0}"]), ("\u{d}\u{22}", &["\u{d}",
+ "\u{22}"]), ("\u{d}\u{308}\u{22}", &["\u{d}", "\u{308}", "\u{22}"]), ("\u{d}\u{27}",
+ &["\u{d}", "\u{27}"]), ("\u{d}\u{308}\u{27}", &["\u{d}", "\u{308}", "\u{27}"]),
+ ("\u{d}\u{231a}", &["\u{d}", "\u{231a}"]), ("\u{d}\u{308}\u{231a}", &["\u{d}", "\u{308}",
+ "\u{231a}"]), ("\u{d}\u{20}", &["\u{d}", "\u{20}"]), ("\u{d}\u{308}\u{20}", &["\u{d}",
+ "\u{308}", "\u{20}"]), ("\u{d}\u{ad}", &["\u{d}", "\u{ad}"]), ("\u{d}\u{308}\u{ad}",
+ &["\u{d}", "\u{308}\u{ad}"]), ("\u{d}\u{300}", &["\u{d}", "\u{300}"]),
+ ("\u{d}\u{308}\u{300}", &["\u{d}", "\u{308}\u{300}"]), ("\u{d}\u{200d}", &["\u{d}",
+ "\u{200d}"]), ("\u{d}\u{308}\u{200d}", &["\u{d}", "\u{308}\u{200d}"]),
+ ("\u{d}\u{61}\u{2060}", &["\u{d}", "\u{61}\u{2060}"]), ("\u{d}\u{308}\u{61}\u{2060}",
+ &["\u{d}", "\u{308}", "\u{61}\u{2060}"]), ("\u{d}\u{61}\u{3a}", &["\u{d}", "\u{61}",
+ "\u{3a}"]), ("\u{d}\u{308}\u{61}\u{3a}", &["\u{d}", "\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{d}\u{61}\u{27}", &["\u{d}", "\u{61}", "\u{27}"]), ("\u{d}\u{308}\u{61}\u{27}",
+ &["\u{d}", "\u{308}", "\u{61}", "\u{27}"]), ("\u{d}\u{61}\u{27}\u{2060}", &["\u{d}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{d}\u{308}\u{61}\u{27}\u{2060}", &["\u{d}", "\u{308}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{d}\u{61}\u{2c}", &["\u{d}", "\u{61}", "\u{2c}"]),
+ ("\u{d}\u{308}\u{61}\u{2c}", &["\u{d}", "\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{d}\u{31}\u{3a}", &["\u{d}", "\u{31}", "\u{3a}"]), ("\u{d}\u{308}\u{31}\u{3a}",
+ &["\u{d}", "\u{308}", "\u{31}", "\u{3a}"]), ("\u{d}\u{31}\u{27}", &["\u{d}", "\u{31}",
+ "\u{27}"]), ("\u{d}\u{308}\u{31}\u{27}", &["\u{d}", "\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{d}\u{31}\u{2c}", &["\u{d}", "\u{31}", "\u{2c}"]), ("\u{d}\u{308}\u{31}\u{2c}",
+ &["\u{d}", "\u{308}", "\u{31}", "\u{2c}"]), ("\u{d}\u{31}\u{2e}\u{2060}", &["\u{d}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{d}\u{308}\u{31}\u{2e}\u{2060}", &["\u{d}", "\u{308}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{a}\u{1}", &["\u{a}", "\u{1}"]), ("\u{a}\u{308}\u{1}",
+ &["\u{a}", "\u{308}", "\u{1}"]), ("\u{a}\u{d}", &["\u{a}", "\u{d}"]), ("\u{a}\u{308}\u{d}",
+ &["\u{a}", "\u{308}", "\u{d}"]), ("\u{a}\u{a}", &["\u{a}", "\u{a}"]), ("\u{a}\u{308}\u{a}",
+ &["\u{a}", "\u{308}", "\u{a}"]), ("\u{a}\u{b}", &["\u{a}", "\u{b}"]), ("\u{a}\u{308}\u{b}",
+ &["\u{a}", "\u{308}", "\u{b}"]), ("\u{a}\u{3031}", &["\u{a}", "\u{3031}"]),
+ ("\u{a}\u{308}\u{3031}", &["\u{a}", "\u{308}", "\u{3031}"]), ("\u{a}\u{41}", &["\u{a}",
+ "\u{41}"]), ("\u{a}\u{308}\u{41}", &["\u{a}", "\u{308}", "\u{41}"]), ("\u{a}\u{3a}",
+ &["\u{a}", "\u{3a}"]), ("\u{a}\u{308}\u{3a}", &["\u{a}", "\u{308}", "\u{3a}"]),
+ ("\u{a}\u{2c}", &["\u{a}", "\u{2c}"]), ("\u{a}\u{308}\u{2c}", &["\u{a}", "\u{308}",
+ "\u{2c}"]), ("\u{a}\u{2e}", &["\u{a}", "\u{2e}"]), ("\u{a}\u{308}\u{2e}", &["\u{a}",
+ "\u{308}", "\u{2e}"]), ("\u{a}\u{30}", &["\u{a}", "\u{30}"]), ("\u{a}\u{308}\u{30}",
+ &["\u{a}", "\u{308}", "\u{30}"]), ("\u{a}\u{5f}", &["\u{a}", "\u{5f}"]),
+ ("\u{a}\u{308}\u{5f}", &["\u{a}", "\u{308}", "\u{5f}"]), ("\u{a}\u{1f1e6}", &["\u{a}",
+ "\u{1f1e6}"]), ("\u{a}\u{308}\u{1f1e6}", &["\u{a}", "\u{308}", "\u{1f1e6}"]),
+ ("\u{a}\u{5d0}", &["\u{a}", "\u{5d0}"]), ("\u{a}\u{308}\u{5d0}", &["\u{a}", "\u{308}",
+ "\u{5d0}"]), ("\u{a}\u{22}", &["\u{a}", "\u{22}"]), ("\u{a}\u{308}\u{22}", &["\u{a}",
+ "\u{308}", "\u{22}"]), ("\u{a}\u{27}", &["\u{a}", "\u{27}"]), ("\u{a}\u{308}\u{27}",
+ &["\u{a}", "\u{308}", "\u{27}"]), ("\u{a}\u{231a}", &["\u{a}", "\u{231a}"]),
+ ("\u{a}\u{308}\u{231a}", &["\u{a}", "\u{308}", "\u{231a}"]), ("\u{a}\u{20}", &["\u{a}",
+ "\u{20}"]), ("\u{a}\u{308}\u{20}", &["\u{a}", "\u{308}", "\u{20}"]), ("\u{a}\u{ad}",
+ &["\u{a}", "\u{ad}"]), ("\u{a}\u{308}\u{ad}", &["\u{a}", "\u{308}\u{ad}"]), ("\u{a}\u{300}",
+ &["\u{a}", "\u{300}"]), ("\u{a}\u{308}\u{300}", &["\u{a}", "\u{308}\u{300}"]),
+ ("\u{a}\u{200d}", &["\u{a}", "\u{200d}"]), ("\u{a}\u{308}\u{200d}", &["\u{a}",
+ "\u{308}\u{200d}"]), ("\u{a}\u{61}\u{2060}", &["\u{a}", "\u{61}\u{2060}"]),
+ ("\u{a}\u{308}\u{61}\u{2060}", &["\u{a}", "\u{308}", "\u{61}\u{2060}"]),
+ ("\u{a}\u{61}\u{3a}", &["\u{a}", "\u{61}", "\u{3a}"]), ("\u{a}\u{308}\u{61}\u{3a}",
+ &["\u{a}", "\u{308}", "\u{61}", "\u{3a}"]), ("\u{a}\u{61}\u{27}", &["\u{a}", "\u{61}",
+ "\u{27}"]), ("\u{a}\u{308}\u{61}\u{27}", &["\u{a}", "\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{a}\u{61}\u{27}\u{2060}", &["\u{a}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{a}\u{308}\u{61}\u{27}\u{2060}", &["\u{a}", "\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{a}\u{61}\u{2c}", &["\u{a}", "\u{61}", "\u{2c}"]), ("\u{a}\u{308}\u{61}\u{2c}",
+ &["\u{a}", "\u{308}", "\u{61}", "\u{2c}"]), ("\u{a}\u{31}\u{3a}", &["\u{a}", "\u{31}",
+ "\u{3a}"]), ("\u{a}\u{308}\u{31}\u{3a}", &["\u{a}", "\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{a}\u{31}\u{27}", &["\u{a}", "\u{31}", "\u{27}"]), ("\u{a}\u{308}\u{31}\u{27}",
+ &["\u{a}", "\u{308}", "\u{31}", "\u{27}"]), ("\u{a}\u{31}\u{2c}", &["\u{a}", "\u{31}",
+ "\u{2c}"]), ("\u{a}\u{308}\u{31}\u{2c}", &["\u{a}", "\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{a}\u{31}\u{2e}\u{2060}", &["\u{a}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{a}\u{308}\u{31}\u{2e}\u{2060}", &["\u{a}", "\u{308}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{b}\u{1}", &["\u{b}", "\u{1}"]), ("\u{b}\u{308}\u{1}", &["\u{b}", "\u{308}", "\u{1}"]),
+ ("\u{b}\u{d}", &["\u{b}", "\u{d}"]), ("\u{b}\u{308}\u{d}", &["\u{b}", "\u{308}", "\u{d}"]),
+ ("\u{b}\u{a}", &["\u{b}", "\u{a}"]), ("\u{b}\u{308}\u{a}", &["\u{b}", "\u{308}", "\u{a}"]),
+ ("\u{b}\u{b}", &["\u{b}", "\u{b}"]), ("\u{b}\u{308}\u{b}", &["\u{b}", "\u{308}", "\u{b}"]),
+ ("\u{b}\u{3031}", &["\u{b}", "\u{3031}"]), ("\u{b}\u{308}\u{3031}", &["\u{b}", "\u{308}",
+ "\u{3031}"]), ("\u{b}\u{41}", &["\u{b}", "\u{41}"]), ("\u{b}\u{308}\u{41}", &["\u{b}",
+ "\u{308}", "\u{41}"]), ("\u{b}\u{3a}", &["\u{b}", "\u{3a}"]), ("\u{b}\u{308}\u{3a}",
+ &["\u{b}", "\u{308}", "\u{3a}"]), ("\u{b}\u{2c}", &["\u{b}", "\u{2c}"]),
+ ("\u{b}\u{308}\u{2c}", &["\u{b}", "\u{308}", "\u{2c}"]), ("\u{b}\u{2e}", &["\u{b}",
+ "\u{2e}"]), ("\u{b}\u{308}\u{2e}", &["\u{b}", "\u{308}", "\u{2e}"]), ("\u{b}\u{30}",
+ &["\u{b}", "\u{30}"]), ("\u{b}\u{308}\u{30}", &["\u{b}", "\u{308}", "\u{30}"]),
+ ("\u{b}\u{5f}", &["\u{b}", "\u{5f}"]), ("\u{b}\u{308}\u{5f}", &["\u{b}", "\u{308}",
+ "\u{5f}"]), ("\u{b}\u{1f1e6}", &["\u{b}", "\u{1f1e6}"]), ("\u{b}\u{308}\u{1f1e6}",
+ &["\u{b}", "\u{308}", "\u{1f1e6}"]), ("\u{b}\u{5d0}", &["\u{b}", "\u{5d0}"]),
+ ("\u{b}\u{308}\u{5d0}", &["\u{b}", "\u{308}", "\u{5d0}"]), ("\u{b}\u{22}", &["\u{b}",
+ "\u{22}"]), ("\u{b}\u{308}\u{22}", &["\u{b}", "\u{308}", "\u{22}"]), ("\u{b}\u{27}",
+ &["\u{b}", "\u{27}"]), ("\u{b}\u{308}\u{27}", &["\u{b}", "\u{308}", "\u{27}"]),
+ ("\u{b}\u{231a}", &["\u{b}", "\u{231a}"]), ("\u{b}\u{308}\u{231a}", &["\u{b}", "\u{308}",
+ "\u{231a}"]), ("\u{b}\u{20}", &["\u{b}", "\u{20}"]), ("\u{b}\u{308}\u{20}", &["\u{b}",
+ "\u{308}", "\u{20}"]), ("\u{b}\u{ad}", &["\u{b}", "\u{ad}"]), ("\u{b}\u{308}\u{ad}",
+ &["\u{b}", "\u{308}\u{ad}"]), ("\u{b}\u{300}", &["\u{b}", "\u{300}"]),
+ ("\u{b}\u{308}\u{300}", &["\u{b}", "\u{308}\u{300}"]), ("\u{b}\u{200d}", &["\u{b}",
+ "\u{200d}"]), ("\u{b}\u{308}\u{200d}", &["\u{b}", "\u{308}\u{200d}"]),
+ ("\u{b}\u{61}\u{2060}", &["\u{b}", "\u{61}\u{2060}"]), ("\u{b}\u{308}\u{61}\u{2060}",
+ &["\u{b}", "\u{308}", "\u{61}\u{2060}"]), ("\u{b}\u{61}\u{3a}", &["\u{b}", "\u{61}",
+ "\u{3a}"]), ("\u{b}\u{308}\u{61}\u{3a}", &["\u{b}", "\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{b}\u{61}\u{27}", &["\u{b}", "\u{61}", "\u{27}"]), ("\u{b}\u{308}\u{61}\u{27}",
+ &["\u{b}", "\u{308}", "\u{61}", "\u{27}"]), ("\u{b}\u{61}\u{27}\u{2060}", &["\u{b}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{b}\u{308}\u{61}\u{27}\u{2060}", &["\u{b}", "\u{308}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{b}\u{61}\u{2c}", &["\u{b}", "\u{61}", "\u{2c}"]),
+ ("\u{b}\u{308}\u{61}\u{2c}", &["\u{b}", "\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{b}\u{31}\u{3a}", &["\u{b}", "\u{31}", "\u{3a}"]), ("\u{b}\u{308}\u{31}\u{3a}",
+ &["\u{b}", "\u{308}", "\u{31}", "\u{3a}"]), ("\u{b}\u{31}\u{27}", &["\u{b}", "\u{31}",
+ "\u{27}"]), ("\u{b}\u{308}\u{31}\u{27}", &["\u{b}", "\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{b}\u{31}\u{2c}", &["\u{b}", "\u{31}", "\u{2c}"]), ("\u{b}\u{308}\u{31}\u{2c}",
+ &["\u{b}", "\u{308}", "\u{31}", "\u{2c}"]), ("\u{b}\u{31}\u{2e}\u{2060}", &["\u{b}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{b}\u{308}\u{31}\u{2e}\u{2060}", &["\u{b}", "\u{308}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{3031}\u{1}", &["\u{3031}", "\u{1}"]),
+ ("\u{3031}\u{308}\u{1}", &["\u{3031}\u{308}", "\u{1}"]), ("\u{3031}\u{d}", &["\u{3031}",
+ "\u{d}"]), ("\u{3031}\u{308}\u{d}", &["\u{3031}\u{308}", "\u{d}"]), ("\u{3031}\u{a}",
+ &["\u{3031}", "\u{a}"]), ("\u{3031}\u{308}\u{a}", &["\u{3031}\u{308}", "\u{a}"]),
+ ("\u{3031}\u{b}", &["\u{3031}", "\u{b}"]), ("\u{3031}\u{308}\u{b}", &["\u{3031}\u{308}",
+ "\u{b}"]), ("\u{3031}\u{3031}", &["\u{3031}\u{3031}"]), ("\u{3031}\u{308}\u{3031}",
+ &["\u{3031}\u{308}\u{3031}"]), ("\u{3031}\u{41}", &["\u{3031}", "\u{41}"]),
+ ("\u{3031}\u{308}\u{41}", &["\u{3031}\u{308}", "\u{41}"]), ("\u{3031}\u{3a}", &["\u{3031}",
+ "\u{3a}"]), ("\u{3031}\u{308}\u{3a}", &["\u{3031}\u{308}", "\u{3a}"]), ("\u{3031}\u{2c}",
+ &["\u{3031}", "\u{2c}"]), ("\u{3031}\u{308}\u{2c}", &["\u{3031}\u{308}", "\u{2c}"]),
+ ("\u{3031}\u{2e}", &["\u{3031}", "\u{2e}"]), ("\u{3031}\u{308}\u{2e}", &["\u{3031}\u{308}",
+ "\u{2e}"]), ("\u{3031}\u{30}", &["\u{3031}", "\u{30}"]), ("\u{3031}\u{308}\u{30}",
+ &["\u{3031}\u{308}", "\u{30}"]), ("\u{3031}\u{5f}", &["\u{3031}\u{5f}"]),
+ ("\u{3031}\u{308}\u{5f}", &["\u{3031}\u{308}\u{5f}"]), ("\u{3031}\u{1f1e6}", &["\u{3031}",
+ "\u{1f1e6}"]), ("\u{3031}\u{308}\u{1f1e6}", &["\u{3031}\u{308}", "\u{1f1e6}"]),
+ ("\u{3031}\u{5d0}", &["\u{3031}", "\u{5d0}"]), ("\u{3031}\u{308}\u{5d0}",
+ &["\u{3031}\u{308}", "\u{5d0}"]), ("\u{3031}\u{22}", &["\u{3031}", "\u{22}"]),
+ ("\u{3031}\u{308}\u{22}", &["\u{3031}\u{308}", "\u{22}"]), ("\u{3031}\u{27}", &["\u{3031}",
+ "\u{27}"]), ("\u{3031}\u{308}\u{27}", &["\u{3031}\u{308}", "\u{27}"]), ("\u{3031}\u{231a}",
+ &["\u{3031}", "\u{231a}"]), ("\u{3031}\u{308}\u{231a}", &["\u{3031}\u{308}", "\u{231a}"]),
+ ("\u{3031}\u{20}", &["\u{3031}", "\u{20}"]), ("\u{3031}\u{308}\u{20}", &["\u{3031}\u{308}",
+ "\u{20}"]), ("\u{3031}\u{ad}", &["\u{3031}\u{ad}"]), ("\u{3031}\u{308}\u{ad}",
+ &["\u{3031}\u{308}\u{ad}"]), ("\u{3031}\u{300}", &["\u{3031}\u{300}"]),
+ ("\u{3031}\u{308}\u{300}", &["\u{3031}\u{308}\u{300}"]), ("\u{3031}\u{200d}",
+ &["\u{3031}\u{200d}"]), ("\u{3031}\u{308}\u{200d}", &["\u{3031}\u{308}\u{200d}"]),
+ ("\u{3031}\u{61}\u{2060}", &["\u{3031}", "\u{61}\u{2060}"]),
+ ("\u{3031}\u{308}\u{61}\u{2060}", &["\u{3031}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{3031}\u{61}\u{3a}", &["\u{3031}", "\u{61}", "\u{3a}"]), ("\u{3031}\u{308}\u{61}\u{3a}",
+ &["\u{3031}\u{308}", "\u{61}", "\u{3a}"]), ("\u{3031}\u{61}\u{27}", &["\u{3031}", "\u{61}",
+ "\u{27}"]), ("\u{3031}\u{308}\u{61}\u{27}", &["\u{3031}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{3031}\u{61}\u{27}\u{2060}", &["\u{3031}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{3031}\u{308}\u{61}\u{27}\u{2060}", &["\u{3031}\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{3031}\u{61}\u{2c}", &["\u{3031}", "\u{61}", "\u{2c}"]), ("\u{3031}\u{308}\u{61}\u{2c}",
+ &["\u{3031}\u{308}", "\u{61}", "\u{2c}"]), ("\u{3031}\u{31}\u{3a}", &["\u{3031}", "\u{31}",
+ "\u{3a}"]), ("\u{3031}\u{308}\u{31}\u{3a}", &["\u{3031}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{3031}\u{31}\u{27}", &["\u{3031}", "\u{31}", "\u{27}"]), ("\u{3031}\u{308}\u{31}\u{27}",
+ &["\u{3031}\u{308}", "\u{31}", "\u{27}"]), ("\u{3031}\u{31}\u{2c}", &["\u{3031}", "\u{31}",
+ "\u{2c}"]), ("\u{3031}\u{308}\u{31}\u{2c}", &["\u{3031}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{3031}\u{31}\u{2e}\u{2060}", &["\u{3031}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{3031}\u{308}\u{31}\u{2e}\u{2060}", &["\u{3031}\u{308}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{41}\u{1}", &["\u{41}", "\u{1}"]), ("\u{41}\u{308}\u{1}", &["\u{41}\u{308}", "\u{1}"]),
+ ("\u{41}\u{d}", &["\u{41}", "\u{d}"]), ("\u{41}\u{308}\u{d}", &["\u{41}\u{308}", "\u{d}"]),
+ ("\u{41}\u{a}", &["\u{41}", "\u{a}"]), ("\u{41}\u{308}\u{a}", &["\u{41}\u{308}", "\u{a}"]),
+ ("\u{41}\u{b}", &["\u{41}", "\u{b}"]), ("\u{41}\u{308}\u{b}", &["\u{41}\u{308}", "\u{b}"]),
+ ("\u{41}\u{3031}", &["\u{41}", "\u{3031}"]), ("\u{41}\u{308}\u{3031}", &["\u{41}\u{308}",
+ "\u{3031}"]), ("\u{41}\u{41}", &["\u{41}\u{41}"]), ("\u{41}\u{308}\u{41}",
+ &["\u{41}\u{308}\u{41}"]), ("\u{41}\u{3a}", &["\u{41}", "\u{3a}"]), ("\u{41}\u{308}\u{3a}",
+ &["\u{41}\u{308}", "\u{3a}"]), ("\u{41}\u{2c}", &["\u{41}", "\u{2c}"]),
+ ("\u{41}\u{308}\u{2c}", &["\u{41}\u{308}", "\u{2c}"]), ("\u{41}\u{2e}", &["\u{41}",
+ "\u{2e}"]), ("\u{41}\u{308}\u{2e}", &["\u{41}\u{308}", "\u{2e}"]), ("\u{41}\u{30}",
+ &["\u{41}\u{30}"]), ("\u{41}\u{308}\u{30}", &["\u{41}\u{308}\u{30}"]), ("\u{41}\u{5f}",
+ &["\u{41}\u{5f}"]), ("\u{41}\u{308}\u{5f}", &["\u{41}\u{308}\u{5f}"]), ("\u{41}\u{1f1e6}",
+ &["\u{41}", "\u{1f1e6}"]), ("\u{41}\u{308}\u{1f1e6}", &["\u{41}\u{308}", "\u{1f1e6}"]),
+ ("\u{41}\u{5d0}", &["\u{41}\u{5d0}"]), ("\u{41}\u{308}\u{5d0}", &["\u{41}\u{308}\u{5d0}"]),
+ ("\u{41}\u{22}", &["\u{41}", "\u{22}"]), ("\u{41}\u{308}\u{22}", &["\u{41}\u{308}",
+ "\u{22}"]), ("\u{41}\u{27}", &["\u{41}", "\u{27}"]), ("\u{41}\u{308}\u{27}",
+ &["\u{41}\u{308}", "\u{27}"]), ("\u{41}\u{231a}", &["\u{41}", "\u{231a}"]),
+ ("\u{41}\u{308}\u{231a}", &["\u{41}\u{308}", "\u{231a}"]), ("\u{41}\u{20}", &["\u{41}",
+ "\u{20}"]), ("\u{41}\u{308}\u{20}", &["\u{41}\u{308}", "\u{20}"]), ("\u{41}\u{ad}",
+ &["\u{41}\u{ad}"]), ("\u{41}\u{308}\u{ad}", &["\u{41}\u{308}\u{ad}"]), ("\u{41}\u{300}",
+ &["\u{41}\u{300}"]), ("\u{41}\u{308}\u{300}", &["\u{41}\u{308}\u{300}"]), ("\u{41}\u{200d}",
+ &["\u{41}\u{200d}"]), ("\u{41}\u{308}\u{200d}", &["\u{41}\u{308}\u{200d}"]),
+ ("\u{41}\u{61}\u{2060}", &["\u{41}\u{61}\u{2060}"]), ("\u{41}\u{308}\u{61}\u{2060}",
+ &["\u{41}\u{308}\u{61}\u{2060}"]), ("\u{41}\u{61}\u{3a}", &["\u{41}\u{61}", "\u{3a}"]),
+ ("\u{41}\u{308}\u{61}\u{3a}", &["\u{41}\u{308}\u{61}", "\u{3a}"]), ("\u{41}\u{61}\u{27}",
+ &["\u{41}\u{61}", "\u{27}"]), ("\u{41}\u{308}\u{61}\u{27}", &["\u{41}\u{308}\u{61}",
+ "\u{27}"]), ("\u{41}\u{61}\u{27}\u{2060}", &["\u{41}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{41}\u{308}\u{61}\u{27}\u{2060}", &["\u{41}\u{308}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{41}\u{61}\u{2c}", &["\u{41}\u{61}", "\u{2c}"]), ("\u{41}\u{308}\u{61}\u{2c}",
+ &["\u{41}\u{308}\u{61}", "\u{2c}"]), ("\u{41}\u{31}\u{3a}", &["\u{41}\u{31}", "\u{3a}"]),
+ ("\u{41}\u{308}\u{31}\u{3a}", &["\u{41}\u{308}\u{31}", "\u{3a}"]), ("\u{41}\u{31}\u{27}",
+ &["\u{41}\u{31}", "\u{27}"]), ("\u{41}\u{308}\u{31}\u{27}", &["\u{41}\u{308}\u{31}",
+ "\u{27}"]), ("\u{41}\u{31}\u{2c}", &["\u{41}\u{31}", "\u{2c}"]),
+ ("\u{41}\u{308}\u{31}\u{2c}", &["\u{41}\u{308}\u{31}", "\u{2c}"]),
+ ("\u{41}\u{31}\u{2e}\u{2060}", &["\u{41}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{41}\u{308}\u{31}\u{2e}\u{2060}", &["\u{41}\u{308}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{3a}\u{1}", &["\u{3a}", "\u{1}"]), ("\u{3a}\u{308}\u{1}", &["\u{3a}\u{308}", "\u{1}"]),
+ ("\u{3a}\u{d}", &["\u{3a}", "\u{d}"]), ("\u{3a}\u{308}\u{d}", &["\u{3a}\u{308}", "\u{d}"]),
+ ("\u{3a}\u{a}", &["\u{3a}", "\u{a}"]), ("\u{3a}\u{308}\u{a}", &["\u{3a}\u{308}", "\u{a}"]),
+ ("\u{3a}\u{b}", &["\u{3a}", "\u{b}"]), ("\u{3a}\u{308}\u{b}", &["\u{3a}\u{308}", "\u{b}"]),
+ ("\u{3a}\u{3031}", &["\u{3a}", "\u{3031}"]), ("\u{3a}\u{308}\u{3031}", &["\u{3a}\u{308}",
+ "\u{3031}"]), ("\u{3a}\u{41}", &["\u{3a}", "\u{41}"]), ("\u{3a}\u{308}\u{41}",
+ &["\u{3a}\u{308}", "\u{41}"]), ("\u{3a}\u{3a}", &["\u{3a}", "\u{3a}"]),
+ ("\u{3a}\u{308}\u{3a}", &["\u{3a}\u{308}", "\u{3a}"]), ("\u{3a}\u{2c}", &["\u{3a}",
+ "\u{2c}"]), ("\u{3a}\u{308}\u{2c}", &["\u{3a}\u{308}", "\u{2c}"]), ("\u{3a}\u{2e}",
+ &["\u{3a}", "\u{2e}"]), ("\u{3a}\u{308}\u{2e}", &["\u{3a}\u{308}", "\u{2e}"]),
+ ("\u{3a}\u{30}", &["\u{3a}", "\u{30}"]), ("\u{3a}\u{308}\u{30}", &["\u{3a}\u{308}",
+ "\u{30}"]), ("\u{3a}\u{5f}", &["\u{3a}", "\u{5f}"]), ("\u{3a}\u{308}\u{5f}",
+ &["\u{3a}\u{308}", "\u{5f}"]), ("\u{3a}\u{1f1e6}", &["\u{3a}", "\u{1f1e6}"]),
+ ("\u{3a}\u{308}\u{1f1e6}", &["\u{3a}\u{308}", "\u{1f1e6}"]), ("\u{3a}\u{5d0}", &["\u{3a}",
+ "\u{5d0}"]), ("\u{3a}\u{308}\u{5d0}", &["\u{3a}\u{308}", "\u{5d0}"]), ("\u{3a}\u{22}",
+ &["\u{3a}", "\u{22}"]), ("\u{3a}\u{308}\u{22}", &["\u{3a}\u{308}", "\u{22}"]),
+ ("\u{3a}\u{27}", &["\u{3a}", "\u{27}"]), ("\u{3a}\u{308}\u{27}", &["\u{3a}\u{308}",
+ "\u{27}"]), ("\u{3a}\u{231a}", &["\u{3a}", "\u{231a}"]), ("\u{3a}\u{308}\u{231a}",
+ &["\u{3a}\u{308}", "\u{231a}"]), ("\u{3a}\u{20}", &["\u{3a}", "\u{20}"]),
+ ("\u{3a}\u{308}\u{20}", &["\u{3a}\u{308}", "\u{20}"]), ("\u{3a}\u{ad}", &["\u{3a}\u{ad}"]),
+ ("\u{3a}\u{308}\u{ad}", &["\u{3a}\u{308}\u{ad}"]), ("\u{3a}\u{300}", &["\u{3a}\u{300}"]),
+ ("\u{3a}\u{308}\u{300}", &["\u{3a}\u{308}\u{300}"]), ("\u{3a}\u{200d}",
+ &["\u{3a}\u{200d}"]), ("\u{3a}\u{308}\u{200d}", &["\u{3a}\u{308}\u{200d}"]),
+ ("\u{3a}\u{61}\u{2060}", &["\u{3a}", "\u{61}\u{2060}"]), ("\u{3a}\u{308}\u{61}\u{2060}",
+ &["\u{3a}\u{308}", "\u{61}\u{2060}"]), ("\u{3a}\u{61}\u{3a}", &["\u{3a}", "\u{61}",
+ "\u{3a}"]), ("\u{3a}\u{308}\u{61}\u{3a}", &["\u{3a}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{3a}\u{61}\u{27}", &["\u{3a}", "\u{61}", "\u{27}"]), ("\u{3a}\u{308}\u{61}\u{27}",
+ &["\u{3a}\u{308}", "\u{61}", "\u{27}"]), ("\u{3a}\u{61}\u{27}\u{2060}", &["\u{3a}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{3a}\u{308}\u{61}\u{27}\u{2060}", &["\u{3a}\u{308}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{3a}\u{61}\u{2c}", &["\u{3a}", "\u{61}", "\u{2c}"]),
+ ("\u{3a}\u{308}\u{61}\u{2c}", &["\u{3a}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{3a}\u{31}\u{3a}", &["\u{3a}", "\u{31}", "\u{3a}"]), ("\u{3a}\u{308}\u{31}\u{3a}",
+ &["\u{3a}\u{308}", "\u{31}", "\u{3a}"]), ("\u{3a}\u{31}\u{27}", &["\u{3a}", "\u{31}",
+ "\u{27}"]), ("\u{3a}\u{308}\u{31}\u{27}", &["\u{3a}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{3a}\u{31}\u{2c}", &["\u{3a}", "\u{31}", "\u{2c}"]), ("\u{3a}\u{308}\u{31}\u{2c}",
+ &["\u{3a}\u{308}", "\u{31}", "\u{2c}"]), ("\u{3a}\u{31}\u{2e}\u{2060}", &["\u{3a}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{3a}\u{308}\u{31}\u{2e}\u{2060}", &["\u{3a}\u{308}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{2c}\u{1}", &["\u{2c}", "\u{1}"]), ("\u{2c}\u{308}\u{1}",
+ &["\u{2c}\u{308}", "\u{1}"]), ("\u{2c}\u{d}", &["\u{2c}", "\u{d}"]), ("\u{2c}\u{308}\u{d}",
+ &["\u{2c}\u{308}", "\u{d}"]), ("\u{2c}\u{a}", &["\u{2c}", "\u{a}"]), ("\u{2c}\u{308}\u{a}",
+ &["\u{2c}\u{308}", "\u{a}"]), ("\u{2c}\u{b}", &["\u{2c}", "\u{b}"]), ("\u{2c}\u{308}\u{b}",
+ &["\u{2c}\u{308}", "\u{b}"]), ("\u{2c}\u{3031}", &["\u{2c}", "\u{3031}"]),
+ ("\u{2c}\u{308}\u{3031}", &["\u{2c}\u{308}", "\u{3031}"]), ("\u{2c}\u{41}", &["\u{2c}",
+ "\u{41}"]), ("\u{2c}\u{308}\u{41}", &["\u{2c}\u{308}", "\u{41}"]), ("\u{2c}\u{3a}",
+ &["\u{2c}", "\u{3a}"]), ("\u{2c}\u{308}\u{3a}", &["\u{2c}\u{308}", "\u{3a}"]),
+ ("\u{2c}\u{2c}", &["\u{2c}", "\u{2c}"]), ("\u{2c}\u{308}\u{2c}", &["\u{2c}\u{308}",
+ "\u{2c}"]), ("\u{2c}\u{2e}", &["\u{2c}", "\u{2e}"]), ("\u{2c}\u{308}\u{2e}",
+ &["\u{2c}\u{308}", "\u{2e}"]), ("\u{2c}\u{30}", &["\u{2c}", "\u{30}"]),
+ ("\u{2c}\u{308}\u{30}", &["\u{2c}\u{308}", "\u{30}"]), ("\u{2c}\u{5f}", &["\u{2c}",
+ "\u{5f}"]), ("\u{2c}\u{308}\u{5f}", &["\u{2c}\u{308}", "\u{5f}"]), ("\u{2c}\u{1f1e6}",
+ &["\u{2c}", "\u{1f1e6}"]), ("\u{2c}\u{308}\u{1f1e6}", &["\u{2c}\u{308}", "\u{1f1e6}"]),
+ ("\u{2c}\u{5d0}", &["\u{2c}", "\u{5d0}"]), ("\u{2c}\u{308}\u{5d0}", &["\u{2c}\u{308}",
+ "\u{5d0}"]), ("\u{2c}\u{22}", &["\u{2c}", "\u{22}"]), ("\u{2c}\u{308}\u{22}",
+ &["\u{2c}\u{308}", "\u{22}"]), ("\u{2c}\u{27}", &["\u{2c}", "\u{27}"]),
+ ("\u{2c}\u{308}\u{27}", &["\u{2c}\u{308}", "\u{27}"]), ("\u{2c}\u{231a}", &["\u{2c}",
+ "\u{231a}"]), ("\u{2c}\u{308}\u{231a}", &["\u{2c}\u{308}", "\u{231a}"]), ("\u{2c}\u{20}",
+ &["\u{2c}", "\u{20}"]), ("\u{2c}\u{308}\u{20}", &["\u{2c}\u{308}", "\u{20}"]),
+ ("\u{2c}\u{ad}", &["\u{2c}\u{ad}"]), ("\u{2c}\u{308}\u{ad}", &["\u{2c}\u{308}\u{ad}"]),
+ ("\u{2c}\u{300}", &["\u{2c}\u{300}"]), ("\u{2c}\u{308}\u{300}", &["\u{2c}\u{308}\u{300}"]),
+ ("\u{2c}\u{200d}", &["\u{2c}\u{200d}"]), ("\u{2c}\u{308}\u{200d}",
+ &["\u{2c}\u{308}\u{200d}"]), ("\u{2c}\u{61}\u{2060}", &["\u{2c}", "\u{61}\u{2060}"]),
+ ("\u{2c}\u{308}\u{61}\u{2060}", &["\u{2c}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{2c}\u{61}\u{3a}", &["\u{2c}", "\u{61}", "\u{3a}"]), ("\u{2c}\u{308}\u{61}\u{3a}",
+ &["\u{2c}\u{308}", "\u{61}", "\u{3a}"]), ("\u{2c}\u{61}\u{27}", &["\u{2c}", "\u{61}",
+ "\u{27}"]), ("\u{2c}\u{308}\u{61}\u{27}", &["\u{2c}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{2c}\u{61}\u{27}\u{2060}", &["\u{2c}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{2c}\u{308}\u{61}\u{27}\u{2060}", &["\u{2c}\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{2c}\u{61}\u{2c}", &["\u{2c}", "\u{61}", "\u{2c}"]), ("\u{2c}\u{308}\u{61}\u{2c}",
+ &["\u{2c}\u{308}", "\u{61}", "\u{2c}"]), ("\u{2c}\u{31}\u{3a}", &["\u{2c}", "\u{31}",
+ "\u{3a}"]), ("\u{2c}\u{308}\u{31}\u{3a}", &["\u{2c}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{2c}\u{31}\u{27}", &["\u{2c}", "\u{31}", "\u{27}"]), ("\u{2c}\u{308}\u{31}\u{27}",
+ &["\u{2c}\u{308}", "\u{31}", "\u{27}"]), ("\u{2c}\u{31}\u{2c}", &["\u{2c}", "\u{31}",
+ "\u{2c}"]), ("\u{2c}\u{308}\u{31}\u{2c}", &["\u{2c}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{2c}\u{31}\u{2e}\u{2060}", &["\u{2c}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{2c}\u{308}\u{31}\u{2e}\u{2060}", &["\u{2c}\u{308}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{2e}\u{1}", &["\u{2e}", "\u{1}"]), ("\u{2e}\u{308}\u{1}", &["\u{2e}\u{308}", "\u{1}"]),
+ ("\u{2e}\u{d}", &["\u{2e}", "\u{d}"]), ("\u{2e}\u{308}\u{d}", &["\u{2e}\u{308}", "\u{d}"]),
+ ("\u{2e}\u{a}", &["\u{2e}", "\u{a}"]), ("\u{2e}\u{308}\u{a}", &["\u{2e}\u{308}", "\u{a}"]),
+ ("\u{2e}\u{b}", &["\u{2e}", "\u{b}"]), ("\u{2e}\u{308}\u{b}", &["\u{2e}\u{308}", "\u{b}"]),
+ ("\u{2e}\u{3031}", &["\u{2e}", "\u{3031}"]), ("\u{2e}\u{308}\u{3031}", &["\u{2e}\u{308}",
+ "\u{3031}"]), ("\u{2e}\u{41}", &["\u{2e}", "\u{41}"]), ("\u{2e}\u{308}\u{41}",
+ &["\u{2e}\u{308}", "\u{41}"]), ("\u{2e}\u{3a}", &["\u{2e}", "\u{3a}"]),
+ ("\u{2e}\u{308}\u{3a}", &["\u{2e}\u{308}", "\u{3a}"]), ("\u{2e}\u{2c}", &["\u{2e}",
+ "\u{2c}"]), ("\u{2e}\u{308}\u{2c}", &["\u{2e}\u{308}", "\u{2c}"]), ("\u{2e}\u{2e}",
+ &["\u{2e}", "\u{2e}"]), ("\u{2e}\u{308}\u{2e}", &["\u{2e}\u{308}", "\u{2e}"]),
+ ("\u{2e}\u{30}", &["\u{2e}", "\u{30}"]), ("\u{2e}\u{308}\u{30}", &["\u{2e}\u{308}",
+ "\u{30}"]), ("\u{2e}\u{5f}", &["\u{2e}", "\u{5f}"]), ("\u{2e}\u{308}\u{5f}",
+ &["\u{2e}\u{308}", "\u{5f}"]), ("\u{2e}\u{1f1e6}", &["\u{2e}", "\u{1f1e6}"]),
+ ("\u{2e}\u{308}\u{1f1e6}", &["\u{2e}\u{308}", "\u{1f1e6}"]), ("\u{2e}\u{5d0}", &["\u{2e}",
+ "\u{5d0}"]), ("\u{2e}\u{308}\u{5d0}", &["\u{2e}\u{308}", "\u{5d0}"]), ("\u{2e}\u{22}",
+ &["\u{2e}", "\u{22}"]), ("\u{2e}\u{308}\u{22}", &["\u{2e}\u{308}", "\u{22}"]),
+ ("\u{2e}\u{27}", &["\u{2e}", "\u{27}"]), ("\u{2e}\u{308}\u{27}", &["\u{2e}\u{308}",
+ "\u{27}"]), ("\u{2e}\u{231a}", &["\u{2e}", "\u{231a}"]), ("\u{2e}\u{308}\u{231a}",
+ &["\u{2e}\u{308}", "\u{231a}"]), ("\u{2e}\u{20}", &["\u{2e}", "\u{20}"]),
+ ("\u{2e}\u{308}\u{20}", &["\u{2e}\u{308}", "\u{20}"]), ("\u{2e}\u{ad}", &["\u{2e}\u{ad}"]),
+ ("\u{2e}\u{308}\u{ad}", &["\u{2e}\u{308}\u{ad}"]), ("\u{2e}\u{300}", &["\u{2e}\u{300}"]),
+ ("\u{2e}\u{308}\u{300}", &["\u{2e}\u{308}\u{300}"]), ("\u{2e}\u{200d}",
+ &["\u{2e}\u{200d}"]), ("\u{2e}\u{308}\u{200d}", &["\u{2e}\u{308}\u{200d}"]),
+ ("\u{2e}\u{61}\u{2060}", &["\u{2e}", "\u{61}\u{2060}"]), ("\u{2e}\u{308}\u{61}\u{2060}",
+ &["\u{2e}\u{308}", "\u{61}\u{2060}"]), ("\u{2e}\u{61}\u{3a}", &["\u{2e}", "\u{61}",
+ "\u{3a}"]), ("\u{2e}\u{308}\u{61}\u{3a}", &["\u{2e}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{2e}\u{61}\u{27}", &["\u{2e}", "\u{61}", "\u{27}"]), ("\u{2e}\u{308}\u{61}\u{27}",
+ &["\u{2e}\u{308}", "\u{61}", "\u{27}"]), ("\u{2e}\u{61}\u{27}\u{2060}", &["\u{2e}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{2e}\u{308}\u{61}\u{27}\u{2060}", &["\u{2e}\u{308}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{2e}\u{61}\u{2c}", &["\u{2e}", "\u{61}", "\u{2c}"]),
+ ("\u{2e}\u{308}\u{61}\u{2c}", &["\u{2e}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{2e}\u{31}\u{3a}", &["\u{2e}", "\u{31}", "\u{3a}"]), ("\u{2e}\u{308}\u{31}\u{3a}",
+ &["\u{2e}\u{308}", "\u{31}", "\u{3a}"]), ("\u{2e}\u{31}\u{27}", &["\u{2e}", "\u{31}",
+ "\u{27}"]), ("\u{2e}\u{308}\u{31}\u{27}", &["\u{2e}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{2e}\u{31}\u{2c}", &["\u{2e}", "\u{31}", "\u{2c}"]), ("\u{2e}\u{308}\u{31}\u{2c}",
+ &["\u{2e}\u{308}", "\u{31}", "\u{2c}"]), ("\u{2e}\u{31}\u{2e}\u{2060}", &["\u{2e}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{2e}\u{308}\u{31}\u{2e}\u{2060}", &["\u{2e}\u{308}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{30}\u{1}", &["\u{30}", "\u{1}"]), ("\u{30}\u{308}\u{1}",
+ &["\u{30}\u{308}", "\u{1}"]), ("\u{30}\u{d}", &["\u{30}", "\u{d}"]), ("\u{30}\u{308}\u{d}",
+ &["\u{30}\u{308}", "\u{d}"]), ("\u{30}\u{a}", &["\u{30}", "\u{a}"]), ("\u{30}\u{308}\u{a}",
+ &["\u{30}\u{308}", "\u{a}"]), ("\u{30}\u{b}", &["\u{30}", "\u{b}"]), ("\u{30}\u{308}\u{b}",
+ &["\u{30}\u{308}", "\u{b}"]), ("\u{30}\u{3031}", &["\u{30}", "\u{3031}"]),
+ ("\u{30}\u{308}\u{3031}", &["\u{30}\u{308}", "\u{3031}"]), ("\u{30}\u{41}",
+ &["\u{30}\u{41}"]), ("\u{30}\u{308}\u{41}", &["\u{30}\u{308}\u{41}"]), ("\u{30}\u{3a}",
+ &["\u{30}", "\u{3a}"]), ("\u{30}\u{308}\u{3a}", &["\u{30}\u{308}", "\u{3a}"]),
+ ("\u{30}\u{2c}", &["\u{30}", "\u{2c}"]), ("\u{30}\u{308}\u{2c}", &["\u{30}\u{308}",
+ "\u{2c}"]), ("\u{30}\u{2e}", &["\u{30}", "\u{2e}"]), ("\u{30}\u{308}\u{2e}",
+ &["\u{30}\u{308}", "\u{2e}"]), ("\u{30}\u{30}", &["\u{30}\u{30}"]), ("\u{30}\u{308}\u{30}",
+ &["\u{30}\u{308}\u{30}"]), ("\u{30}\u{5f}", &["\u{30}\u{5f}"]), ("\u{30}\u{308}\u{5f}",
+ &["\u{30}\u{308}\u{5f}"]), ("\u{30}\u{1f1e6}", &["\u{30}", "\u{1f1e6}"]),
+ ("\u{30}\u{308}\u{1f1e6}", &["\u{30}\u{308}", "\u{1f1e6}"]), ("\u{30}\u{5d0}",
+ &["\u{30}\u{5d0}"]), ("\u{30}\u{308}\u{5d0}", &["\u{30}\u{308}\u{5d0}"]), ("\u{30}\u{22}",
+ &["\u{30}", "\u{22}"]), ("\u{30}\u{308}\u{22}", &["\u{30}\u{308}", "\u{22}"]),
+ ("\u{30}\u{27}", &["\u{30}", "\u{27}"]), ("\u{30}\u{308}\u{27}", &["\u{30}\u{308}",
+ "\u{27}"]), ("\u{30}\u{231a}", &["\u{30}", "\u{231a}"]), ("\u{30}\u{308}\u{231a}",
+ &["\u{30}\u{308}", "\u{231a}"]), ("\u{30}\u{20}", &["\u{30}", "\u{20}"]),
+ ("\u{30}\u{308}\u{20}", &["\u{30}\u{308}", "\u{20}"]), ("\u{30}\u{ad}", &["\u{30}\u{ad}"]),
+ ("\u{30}\u{308}\u{ad}", &["\u{30}\u{308}\u{ad}"]), ("\u{30}\u{300}", &["\u{30}\u{300}"]),
+ ("\u{30}\u{308}\u{300}", &["\u{30}\u{308}\u{300}"]), ("\u{30}\u{200d}",
+ &["\u{30}\u{200d}"]), ("\u{30}\u{308}\u{200d}", &["\u{30}\u{308}\u{200d}"]),
+ ("\u{30}\u{61}\u{2060}", &["\u{30}\u{61}\u{2060}"]), ("\u{30}\u{308}\u{61}\u{2060}",
+ &["\u{30}\u{308}\u{61}\u{2060}"]), ("\u{30}\u{61}\u{3a}", &["\u{30}\u{61}", "\u{3a}"]),
+ ("\u{30}\u{308}\u{61}\u{3a}", &["\u{30}\u{308}\u{61}", "\u{3a}"]), ("\u{30}\u{61}\u{27}",
+ &["\u{30}\u{61}", "\u{27}"]), ("\u{30}\u{308}\u{61}\u{27}", &["\u{30}\u{308}\u{61}",
+ "\u{27}"]), ("\u{30}\u{61}\u{27}\u{2060}", &["\u{30}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{30}\u{308}\u{61}\u{27}\u{2060}", &["\u{30}\u{308}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{30}\u{61}\u{2c}", &["\u{30}\u{61}", "\u{2c}"]), ("\u{30}\u{308}\u{61}\u{2c}",
+ &["\u{30}\u{308}\u{61}", "\u{2c}"]), ("\u{30}\u{31}\u{3a}", &["\u{30}\u{31}", "\u{3a}"]),
+ ("\u{30}\u{308}\u{31}\u{3a}", &["\u{30}\u{308}\u{31}", "\u{3a}"]), ("\u{30}\u{31}\u{27}",
+ &["\u{30}\u{31}", "\u{27}"]), ("\u{30}\u{308}\u{31}\u{27}", &["\u{30}\u{308}\u{31}",
+ "\u{27}"]), ("\u{30}\u{31}\u{2c}", &["\u{30}\u{31}", "\u{2c}"]),
+ ("\u{30}\u{308}\u{31}\u{2c}", &["\u{30}\u{308}\u{31}", "\u{2c}"]),
+ ("\u{30}\u{31}\u{2e}\u{2060}", &["\u{30}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{30}\u{308}\u{31}\u{2e}\u{2060}", &["\u{30}\u{308}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{5f}\u{1}", &["\u{5f}", "\u{1}"]), ("\u{5f}\u{308}\u{1}", &["\u{5f}\u{308}", "\u{1}"]),
+ ("\u{5f}\u{d}", &["\u{5f}", "\u{d}"]), ("\u{5f}\u{308}\u{d}", &["\u{5f}\u{308}", "\u{d}"]),
+ ("\u{5f}\u{a}", &["\u{5f}", "\u{a}"]), ("\u{5f}\u{308}\u{a}", &["\u{5f}\u{308}", "\u{a}"]),
+ ("\u{5f}\u{b}", &["\u{5f}", "\u{b}"]), ("\u{5f}\u{308}\u{b}", &["\u{5f}\u{308}", "\u{b}"]),
+ ("\u{5f}\u{3031}", &["\u{5f}\u{3031}"]), ("\u{5f}\u{308}\u{3031}",
+ &["\u{5f}\u{308}\u{3031}"]), ("\u{5f}\u{41}", &["\u{5f}\u{41}"]), ("\u{5f}\u{308}\u{41}",
+ &["\u{5f}\u{308}\u{41}"]), ("\u{5f}\u{3a}", &["\u{5f}", "\u{3a}"]), ("\u{5f}\u{308}\u{3a}",
+ &["\u{5f}\u{308}", "\u{3a}"]), ("\u{5f}\u{2c}", &["\u{5f}", "\u{2c}"]),
+ ("\u{5f}\u{308}\u{2c}", &["\u{5f}\u{308}", "\u{2c}"]), ("\u{5f}\u{2e}", &["\u{5f}",
+ "\u{2e}"]), ("\u{5f}\u{308}\u{2e}", &["\u{5f}\u{308}", "\u{2e}"]), ("\u{5f}\u{30}",
+ &["\u{5f}\u{30}"]), ("\u{5f}\u{308}\u{30}", &["\u{5f}\u{308}\u{30}"]), ("\u{5f}\u{5f}",
+ &["\u{5f}\u{5f}"]), ("\u{5f}\u{308}\u{5f}", &["\u{5f}\u{308}\u{5f}"]), ("\u{5f}\u{1f1e6}",
+ &["\u{5f}", "\u{1f1e6}"]), ("\u{5f}\u{308}\u{1f1e6}", &["\u{5f}\u{308}", "\u{1f1e6}"]),
+ ("\u{5f}\u{5d0}", &["\u{5f}\u{5d0}"]), ("\u{5f}\u{308}\u{5d0}", &["\u{5f}\u{308}\u{5d0}"]),
+ ("\u{5f}\u{22}", &["\u{5f}", "\u{22}"]), ("\u{5f}\u{308}\u{22}", &["\u{5f}\u{308}",
+ "\u{22}"]), ("\u{5f}\u{27}", &["\u{5f}", "\u{27}"]), ("\u{5f}\u{308}\u{27}",
+ &["\u{5f}\u{308}", "\u{27}"]), ("\u{5f}\u{231a}", &["\u{5f}", "\u{231a}"]),
+ ("\u{5f}\u{308}\u{231a}", &["\u{5f}\u{308}", "\u{231a}"]), ("\u{5f}\u{20}", &["\u{5f}",
+ "\u{20}"]), ("\u{5f}\u{308}\u{20}", &["\u{5f}\u{308}", "\u{20}"]), ("\u{5f}\u{ad}",
+ &["\u{5f}\u{ad}"]), ("\u{5f}\u{308}\u{ad}", &["\u{5f}\u{308}\u{ad}"]), ("\u{5f}\u{300}",
+ &["\u{5f}\u{300}"]), ("\u{5f}\u{308}\u{300}", &["\u{5f}\u{308}\u{300}"]), ("\u{5f}\u{200d}",
+ &["\u{5f}\u{200d}"]), ("\u{5f}\u{308}\u{200d}", &["\u{5f}\u{308}\u{200d}"]),
+ ("\u{5f}\u{61}\u{2060}", &["\u{5f}\u{61}\u{2060}"]), ("\u{5f}\u{308}\u{61}\u{2060}",
+ &["\u{5f}\u{308}\u{61}\u{2060}"]), ("\u{5f}\u{61}\u{3a}", &["\u{5f}\u{61}", "\u{3a}"]),
+ ("\u{5f}\u{308}\u{61}\u{3a}", &["\u{5f}\u{308}\u{61}", "\u{3a}"]), ("\u{5f}\u{61}\u{27}",
+ &["\u{5f}\u{61}", "\u{27}"]), ("\u{5f}\u{308}\u{61}\u{27}", &["\u{5f}\u{308}\u{61}",
+ "\u{27}"]), ("\u{5f}\u{61}\u{27}\u{2060}", &["\u{5f}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{5f}\u{308}\u{61}\u{27}\u{2060}", &["\u{5f}\u{308}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{5f}\u{61}\u{2c}", &["\u{5f}\u{61}", "\u{2c}"]), ("\u{5f}\u{308}\u{61}\u{2c}",
+ &["\u{5f}\u{308}\u{61}", "\u{2c}"]), ("\u{5f}\u{31}\u{3a}", &["\u{5f}\u{31}", "\u{3a}"]),
+ ("\u{5f}\u{308}\u{31}\u{3a}", &["\u{5f}\u{308}\u{31}", "\u{3a}"]), ("\u{5f}\u{31}\u{27}",
+ &["\u{5f}\u{31}", "\u{27}"]), ("\u{5f}\u{308}\u{31}\u{27}", &["\u{5f}\u{308}\u{31}",
+ "\u{27}"]), ("\u{5f}\u{31}\u{2c}", &["\u{5f}\u{31}", "\u{2c}"]),
+ ("\u{5f}\u{308}\u{31}\u{2c}", &["\u{5f}\u{308}\u{31}", "\u{2c}"]),
+ ("\u{5f}\u{31}\u{2e}\u{2060}", &["\u{5f}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{5f}\u{308}\u{31}\u{2e}\u{2060}", &["\u{5f}\u{308}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{1f1e6}\u{1}", &["\u{1f1e6}", "\u{1}"]), ("\u{1f1e6}\u{308}\u{1}", &["\u{1f1e6}\u{308}",
+ "\u{1}"]), ("\u{1f1e6}\u{d}", &["\u{1f1e6}", "\u{d}"]), ("\u{1f1e6}\u{308}\u{d}",
+ &["\u{1f1e6}\u{308}", "\u{d}"]), ("\u{1f1e6}\u{a}", &["\u{1f1e6}", "\u{a}"]),
+ ("\u{1f1e6}\u{308}\u{a}", &["\u{1f1e6}\u{308}", "\u{a}"]), ("\u{1f1e6}\u{b}", &["\u{1f1e6}",
+ "\u{b}"]), ("\u{1f1e6}\u{308}\u{b}", &["\u{1f1e6}\u{308}", "\u{b}"]), ("\u{1f1e6}\u{3031}",
+ &["\u{1f1e6}", "\u{3031}"]), ("\u{1f1e6}\u{308}\u{3031}", &["\u{1f1e6}\u{308}",
+ "\u{3031}"]), ("\u{1f1e6}\u{41}", &["\u{1f1e6}", "\u{41}"]), ("\u{1f1e6}\u{308}\u{41}",
+ &["\u{1f1e6}\u{308}", "\u{41}"]), ("\u{1f1e6}\u{3a}", &["\u{1f1e6}", "\u{3a}"]),
+ ("\u{1f1e6}\u{308}\u{3a}", &["\u{1f1e6}\u{308}", "\u{3a}"]), ("\u{1f1e6}\u{2c}",
+ &["\u{1f1e6}", "\u{2c}"]), ("\u{1f1e6}\u{308}\u{2c}", &["\u{1f1e6}\u{308}", "\u{2c}"]),
+ ("\u{1f1e6}\u{2e}", &["\u{1f1e6}", "\u{2e}"]), ("\u{1f1e6}\u{308}\u{2e}",
+ &["\u{1f1e6}\u{308}", "\u{2e}"]), ("\u{1f1e6}\u{30}", &["\u{1f1e6}", "\u{30}"]),
+ ("\u{1f1e6}\u{308}\u{30}", &["\u{1f1e6}\u{308}", "\u{30}"]), ("\u{1f1e6}\u{5f}",
+ &["\u{1f1e6}", "\u{5f}"]), ("\u{1f1e6}\u{308}\u{5f}", &["\u{1f1e6}\u{308}", "\u{5f}"]),
+ ("\u{1f1e6}\u{1f1e6}", &["\u{1f1e6}\u{1f1e6}"]), ("\u{1f1e6}\u{308}\u{1f1e6}",
+ &["\u{1f1e6}\u{308}\u{1f1e6}"]), ("\u{1f1e6}\u{5d0}", &["\u{1f1e6}", "\u{5d0}"]),
+ ("\u{1f1e6}\u{308}\u{5d0}", &["\u{1f1e6}\u{308}", "\u{5d0}"]), ("\u{1f1e6}\u{22}",
+ &["\u{1f1e6}", "\u{22}"]), ("\u{1f1e6}\u{308}\u{22}", &["\u{1f1e6}\u{308}", "\u{22}"]),
+ ("\u{1f1e6}\u{27}", &["\u{1f1e6}", "\u{27}"]), ("\u{1f1e6}\u{308}\u{27}",
+ &["\u{1f1e6}\u{308}", "\u{27}"]), ("\u{1f1e6}\u{231a}", &["\u{1f1e6}", "\u{231a}"]),
+ ("\u{1f1e6}\u{308}\u{231a}", &["\u{1f1e6}\u{308}", "\u{231a}"]), ("\u{1f1e6}\u{20}",
+ &["\u{1f1e6}", "\u{20}"]), ("\u{1f1e6}\u{308}\u{20}", &["\u{1f1e6}\u{308}", "\u{20}"]),
+ ("\u{1f1e6}\u{ad}", &["\u{1f1e6}\u{ad}"]), ("\u{1f1e6}\u{308}\u{ad}",
+ &["\u{1f1e6}\u{308}\u{ad}"]), ("\u{1f1e6}\u{300}", &["\u{1f1e6}\u{300}"]),
+ ("\u{1f1e6}\u{308}\u{300}", &["\u{1f1e6}\u{308}\u{300}"]), ("\u{1f1e6}\u{200d}",
+ &["\u{1f1e6}\u{200d}"]), ("\u{1f1e6}\u{308}\u{200d}", &["\u{1f1e6}\u{308}\u{200d}"]),
+ ("\u{1f1e6}\u{61}\u{2060}", &["\u{1f1e6}", "\u{61}\u{2060}"]),
+ ("\u{1f1e6}\u{308}\u{61}\u{2060}", &["\u{1f1e6}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{1f1e6}\u{61}\u{3a}", &["\u{1f1e6}", "\u{61}", "\u{3a}"]),
+ ("\u{1f1e6}\u{308}\u{61}\u{3a}", &["\u{1f1e6}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{1f1e6}\u{61}\u{27}", &["\u{1f1e6}", "\u{61}", "\u{27}"]),
+ ("\u{1f1e6}\u{308}\u{61}\u{27}", &["\u{1f1e6}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{1f1e6}\u{61}\u{27}\u{2060}", &["\u{1f1e6}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{1f1e6}\u{308}\u{61}\u{27}\u{2060}", &["\u{1f1e6}\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{1f1e6}\u{61}\u{2c}", &["\u{1f1e6}", "\u{61}", "\u{2c}"]),
+ ("\u{1f1e6}\u{308}\u{61}\u{2c}", &["\u{1f1e6}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{1f1e6}\u{31}\u{3a}", &["\u{1f1e6}", "\u{31}", "\u{3a}"]),
+ ("\u{1f1e6}\u{308}\u{31}\u{3a}", &["\u{1f1e6}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{1f1e6}\u{31}\u{27}", &["\u{1f1e6}", "\u{31}", "\u{27}"]),
+ ("\u{1f1e6}\u{308}\u{31}\u{27}", &["\u{1f1e6}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{1f1e6}\u{31}\u{2c}", &["\u{1f1e6}", "\u{31}", "\u{2c}"]),
+ ("\u{1f1e6}\u{308}\u{31}\u{2c}", &["\u{1f1e6}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{1f1e6}\u{31}\u{2e}\u{2060}", &["\u{1f1e6}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{1f1e6}\u{308}\u{31}\u{2e}\u{2060}", &["\u{1f1e6}\u{308}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{5d0}\u{1}", &["\u{5d0}", "\u{1}"]), ("\u{5d0}\u{308}\u{1}", &["\u{5d0}\u{308}",
+ "\u{1}"]), ("\u{5d0}\u{d}", &["\u{5d0}", "\u{d}"]), ("\u{5d0}\u{308}\u{d}",
+ &["\u{5d0}\u{308}", "\u{d}"]), ("\u{5d0}\u{a}", &["\u{5d0}", "\u{a}"]),
+ ("\u{5d0}\u{308}\u{a}", &["\u{5d0}\u{308}", "\u{a}"]), ("\u{5d0}\u{b}", &["\u{5d0}",
+ "\u{b}"]), ("\u{5d0}\u{308}\u{b}", &["\u{5d0}\u{308}", "\u{b}"]), ("\u{5d0}\u{3031}",
+ &["\u{5d0}", "\u{3031}"]), ("\u{5d0}\u{308}\u{3031}", &["\u{5d0}\u{308}", "\u{3031}"]),
+ ("\u{5d0}\u{41}", &["\u{5d0}\u{41}"]), ("\u{5d0}\u{308}\u{41}", &["\u{5d0}\u{308}\u{41}"]),
+ ("\u{5d0}\u{3a}", &["\u{5d0}", "\u{3a}"]), ("\u{5d0}\u{308}\u{3a}", &["\u{5d0}\u{308}",
+ "\u{3a}"]), ("\u{5d0}\u{2c}", &["\u{5d0}", "\u{2c}"]), ("\u{5d0}\u{308}\u{2c}",
+ &["\u{5d0}\u{308}", "\u{2c}"]), ("\u{5d0}\u{2e}", &["\u{5d0}", "\u{2e}"]),
+ ("\u{5d0}\u{308}\u{2e}", &["\u{5d0}\u{308}", "\u{2e}"]), ("\u{5d0}\u{30}",
+ &["\u{5d0}\u{30}"]), ("\u{5d0}\u{308}\u{30}", &["\u{5d0}\u{308}\u{30}"]), ("\u{5d0}\u{5f}",
+ &["\u{5d0}\u{5f}"]), ("\u{5d0}\u{308}\u{5f}", &["\u{5d0}\u{308}\u{5f}"]),
+ ("\u{5d0}\u{1f1e6}", &["\u{5d0}", "\u{1f1e6}"]), ("\u{5d0}\u{308}\u{1f1e6}",
+ &["\u{5d0}\u{308}", "\u{1f1e6}"]), ("\u{5d0}\u{5d0}", &["\u{5d0}\u{5d0}"]),
+ ("\u{5d0}\u{308}\u{5d0}", &["\u{5d0}\u{308}\u{5d0}"]), ("\u{5d0}\u{22}", &["\u{5d0}",
+ "\u{22}"]), ("\u{5d0}\u{308}\u{22}", &["\u{5d0}\u{308}", "\u{22}"]), ("\u{5d0}\u{27}",
+ &["\u{5d0}\u{27}"]), ("\u{5d0}\u{308}\u{27}", &["\u{5d0}\u{308}\u{27}"]),
+ ("\u{5d0}\u{231a}", &["\u{5d0}", "\u{231a}"]), ("\u{5d0}\u{308}\u{231a}",
+ &["\u{5d0}\u{308}", "\u{231a}"]), ("\u{5d0}\u{20}", &["\u{5d0}", "\u{20}"]),
+ ("\u{5d0}\u{308}\u{20}", &["\u{5d0}\u{308}", "\u{20}"]), ("\u{5d0}\u{ad}",
+ &["\u{5d0}\u{ad}"]), ("\u{5d0}\u{308}\u{ad}", &["\u{5d0}\u{308}\u{ad}"]), ("\u{5d0}\u{300}",
+ &["\u{5d0}\u{300}"]), ("\u{5d0}\u{308}\u{300}", &["\u{5d0}\u{308}\u{300}"]),
+ ("\u{5d0}\u{200d}", &["\u{5d0}\u{200d}"]), ("\u{5d0}\u{308}\u{200d}",
+ &["\u{5d0}\u{308}\u{200d}"]), ("\u{5d0}\u{61}\u{2060}", &["\u{5d0}\u{61}\u{2060}"]),
+ ("\u{5d0}\u{308}\u{61}\u{2060}", &["\u{5d0}\u{308}\u{61}\u{2060}"]), ("\u{5d0}\u{61}\u{3a}",
+ &["\u{5d0}\u{61}", "\u{3a}"]), ("\u{5d0}\u{308}\u{61}\u{3a}", &["\u{5d0}\u{308}\u{61}",
+ "\u{3a}"]), ("\u{5d0}\u{61}\u{27}", &["\u{5d0}\u{61}", "\u{27}"]),
+ ("\u{5d0}\u{308}\u{61}\u{27}", &["\u{5d0}\u{308}\u{61}", "\u{27}"]),
+ ("\u{5d0}\u{61}\u{27}\u{2060}", &["\u{5d0}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{5d0}\u{308}\u{61}\u{27}\u{2060}", &["\u{5d0}\u{308}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{5d0}\u{61}\u{2c}", &["\u{5d0}\u{61}", "\u{2c}"]), ("\u{5d0}\u{308}\u{61}\u{2c}",
+ &["\u{5d0}\u{308}\u{61}", "\u{2c}"]), ("\u{5d0}\u{31}\u{3a}", &["\u{5d0}\u{31}", "\u{3a}"]),
+ ("\u{5d0}\u{308}\u{31}\u{3a}", &["\u{5d0}\u{308}\u{31}", "\u{3a}"]), ("\u{5d0}\u{31}\u{27}",
+ &["\u{5d0}\u{31}", "\u{27}"]), ("\u{5d0}\u{308}\u{31}\u{27}", &["\u{5d0}\u{308}\u{31}",
+ "\u{27}"]), ("\u{5d0}\u{31}\u{2c}", &["\u{5d0}\u{31}", "\u{2c}"]),
+ ("\u{5d0}\u{308}\u{31}\u{2c}", &["\u{5d0}\u{308}\u{31}", "\u{2c}"]),
+ ("\u{5d0}\u{31}\u{2e}\u{2060}", &["\u{5d0}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{5d0}\u{308}\u{31}\u{2e}\u{2060}", &["\u{5d0}\u{308}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{22}\u{1}", &["\u{22}", "\u{1}"]), ("\u{22}\u{308}\u{1}", &["\u{22}\u{308}", "\u{1}"]),
+ ("\u{22}\u{d}", &["\u{22}", "\u{d}"]), ("\u{22}\u{308}\u{d}", &["\u{22}\u{308}", "\u{d}"]),
+ ("\u{22}\u{a}", &["\u{22}", "\u{a}"]), ("\u{22}\u{308}\u{a}", &["\u{22}\u{308}", "\u{a}"]),
+ ("\u{22}\u{b}", &["\u{22}", "\u{b}"]), ("\u{22}\u{308}\u{b}", &["\u{22}\u{308}", "\u{b}"]),
+ ("\u{22}\u{3031}", &["\u{22}", "\u{3031}"]), ("\u{22}\u{308}\u{3031}", &["\u{22}\u{308}",
+ "\u{3031}"]), ("\u{22}\u{41}", &["\u{22}", "\u{41}"]), ("\u{22}\u{308}\u{41}",
+ &["\u{22}\u{308}", "\u{41}"]), ("\u{22}\u{3a}", &["\u{22}", "\u{3a}"]),
+ ("\u{22}\u{308}\u{3a}", &["\u{22}\u{308}", "\u{3a}"]), ("\u{22}\u{2c}", &["\u{22}",
+ "\u{2c}"]), ("\u{22}\u{308}\u{2c}", &["\u{22}\u{308}", "\u{2c}"]), ("\u{22}\u{2e}",
+ &["\u{22}", "\u{2e}"]), ("\u{22}\u{308}\u{2e}", &["\u{22}\u{308}", "\u{2e}"]),
+ ("\u{22}\u{30}", &["\u{22}", "\u{30}"]), ("\u{22}\u{308}\u{30}", &["\u{22}\u{308}",
+ "\u{30}"]), ("\u{22}\u{5f}", &["\u{22}", "\u{5f}"]), ("\u{22}\u{308}\u{5f}",
+ &["\u{22}\u{308}", "\u{5f}"]), ("\u{22}\u{1f1e6}", &["\u{22}", "\u{1f1e6}"]),
+ ("\u{22}\u{308}\u{1f1e6}", &["\u{22}\u{308}", "\u{1f1e6}"]), ("\u{22}\u{5d0}", &["\u{22}",
+ "\u{5d0}"]), ("\u{22}\u{308}\u{5d0}", &["\u{22}\u{308}", "\u{5d0}"]), ("\u{22}\u{22}",
+ &["\u{22}", "\u{22}"]), ("\u{22}\u{308}\u{22}", &["\u{22}\u{308}", "\u{22}"]),
+ ("\u{22}\u{27}", &["\u{22}", "\u{27}"]), ("\u{22}\u{308}\u{27}", &["\u{22}\u{308}",
+ "\u{27}"]), ("\u{22}\u{231a}", &["\u{22}", "\u{231a}"]), ("\u{22}\u{308}\u{231a}",
+ &["\u{22}\u{308}", "\u{231a}"]), ("\u{22}\u{20}", &["\u{22}", "\u{20}"]),
+ ("\u{22}\u{308}\u{20}", &["\u{22}\u{308}", "\u{20}"]), ("\u{22}\u{ad}", &["\u{22}\u{ad}"]),
+ ("\u{22}\u{308}\u{ad}", &["\u{22}\u{308}\u{ad}"]), ("\u{22}\u{300}", &["\u{22}\u{300}"]),
+ ("\u{22}\u{308}\u{300}", &["\u{22}\u{308}\u{300}"]), ("\u{22}\u{200d}",
+ &["\u{22}\u{200d}"]), ("\u{22}\u{308}\u{200d}", &["\u{22}\u{308}\u{200d}"]),
+ ("\u{22}\u{61}\u{2060}", &["\u{22}", "\u{61}\u{2060}"]), ("\u{22}\u{308}\u{61}\u{2060}",
+ &["\u{22}\u{308}", "\u{61}\u{2060}"]), ("\u{22}\u{61}\u{3a}", &["\u{22}", "\u{61}",
+ "\u{3a}"]), ("\u{22}\u{308}\u{61}\u{3a}", &["\u{22}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{22}\u{61}\u{27}", &["\u{22}", "\u{61}", "\u{27}"]), ("\u{22}\u{308}\u{61}\u{27}",
+ &["\u{22}\u{308}", "\u{61}", "\u{27}"]), ("\u{22}\u{61}\u{27}\u{2060}", &["\u{22}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{22}\u{308}\u{61}\u{27}\u{2060}", &["\u{22}\u{308}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{22}\u{61}\u{2c}", &["\u{22}", "\u{61}", "\u{2c}"]),
+ ("\u{22}\u{308}\u{61}\u{2c}", &["\u{22}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{22}\u{31}\u{3a}", &["\u{22}", "\u{31}", "\u{3a}"]), ("\u{22}\u{308}\u{31}\u{3a}",
+ &["\u{22}\u{308}", "\u{31}", "\u{3a}"]), ("\u{22}\u{31}\u{27}", &["\u{22}", "\u{31}",
+ "\u{27}"]), ("\u{22}\u{308}\u{31}\u{27}", &["\u{22}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{22}\u{31}\u{2c}", &["\u{22}", "\u{31}", "\u{2c}"]), ("\u{22}\u{308}\u{31}\u{2c}",
+ &["\u{22}\u{308}", "\u{31}", "\u{2c}"]), ("\u{22}\u{31}\u{2e}\u{2060}", &["\u{22}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{22}\u{308}\u{31}\u{2e}\u{2060}", &["\u{22}\u{308}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{27}\u{1}", &["\u{27}", "\u{1}"]), ("\u{27}\u{308}\u{1}",
+ &["\u{27}\u{308}", "\u{1}"]), ("\u{27}\u{d}", &["\u{27}", "\u{d}"]), ("\u{27}\u{308}\u{d}",
+ &["\u{27}\u{308}", "\u{d}"]), ("\u{27}\u{a}", &["\u{27}", "\u{a}"]), ("\u{27}\u{308}\u{a}",
+ &["\u{27}\u{308}", "\u{a}"]), ("\u{27}\u{b}", &["\u{27}", "\u{b}"]), ("\u{27}\u{308}\u{b}",
+ &["\u{27}\u{308}", "\u{b}"]), ("\u{27}\u{3031}", &["\u{27}", "\u{3031}"]),
+ ("\u{27}\u{308}\u{3031}", &["\u{27}\u{308}", "\u{3031}"]), ("\u{27}\u{41}", &["\u{27}",
+ "\u{41}"]), ("\u{27}\u{308}\u{41}", &["\u{27}\u{308}", "\u{41}"]), ("\u{27}\u{3a}",
+ &["\u{27}", "\u{3a}"]), ("\u{27}\u{308}\u{3a}", &["\u{27}\u{308}", "\u{3a}"]),
+ ("\u{27}\u{2c}", &["\u{27}", "\u{2c}"]), ("\u{27}\u{308}\u{2c}", &["\u{27}\u{308}",
+ "\u{2c}"]), ("\u{27}\u{2e}", &["\u{27}", "\u{2e}"]), ("\u{27}\u{308}\u{2e}",
+ &["\u{27}\u{308}", "\u{2e}"]), ("\u{27}\u{30}", &["\u{27}", "\u{30}"]),
+ ("\u{27}\u{308}\u{30}", &["\u{27}\u{308}", "\u{30}"]), ("\u{27}\u{5f}", &["\u{27}",
+ "\u{5f}"]), ("\u{27}\u{308}\u{5f}", &["\u{27}\u{308}", "\u{5f}"]), ("\u{27}\u{1f1e6}",
+ &["\u{27}", "\u{1f1e6}"]), ("\u{27}\u{308}\u{1f1e6}", &["\u{27}\u{308}", "\u{1f1e6}"]),
+ ("\u{27}\u{5d0}", &["\u{27}", "\u{5d0}"]), ("\u{27}\u{308}\u{5d0}", &["\u{27}\u{308}",
+ "\u{5d0}"]), ("\u{27}\u{22}", &["\u{27}", "\u{22}"]), ("\u{27}\u{308}\u{22}",
+ &["\u{27}\u{308}", "\u{22}"]), ("\u{27}\u{27}", &["\u{27}", "\u{27}"]),
+ ("\u{27}\u{308}\u{27}", &["\u{27}\u{308}", "\u{27}"]), ("\u{27}\u{231a}", &["\u{27}",
+ "\u{231a}"]), ("\u{27}\u{308}\u{231a}", &["\u{27}\u{308}", "\u{231a}"]), ("\u{27}\u{20}",
+ &["\u{27}", "\u{20}"]), ("\u{27}\u{308}\u{20}", &["\u{27}\u{308}", "\u{20}"]),
+ ("\u{27}\u{ad}", &["\u{27}\u{ad}"]), ("\u{27}\u{308}\u{ad}", &["\u{27}\u{308}\u{ad}"]),
+ ("\u{27}\u{300}", &["\u{27}\u{300}"]), ("\u{27}\u{308}\u{300}", &["\u{27}\u{308}\u{300}"]),
+ ("\u{27}\u{200d}", &["\u{27}\u{200d}"]), ("\u{27}\u{308}\u{200d}",
+ &["\u{27}\u{308}\u{200d}"]), ("\u{27}\u{61}\u{2060}", &["\u{27}", "\u{61}\u{2060}"]),
+ ("\u{27}\u{308}\u{61}\u{2060}", &["\u{27}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{27}\u{61}\u{3a}", &["\u{27}", "\u{61}", "\u{3a}"]), ("\u{27}\u{308}\u{61}\u{3a}",
+ &["\u{27}\u{308}", "\u{61}", "\u{3a}"]), ("\u{27}\u{61}\u{27}", &["\u{27}", "\u{61}",
+ "\u{27}"]), ("\u{27}\u{308}\u{61}\u{27}", &["\u{27}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{27}\u{61}\u{27}\u{2060}", &["\u{27}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{27}\u{308}\u{61}\u{27}\u{2060}", &["\u{27}\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{27}\u{61}\u{2c}", &["\u{27}", "\u{61}", "\u{2c}"]), ("\u{27}\u{308}\u{61}\u{2c}",
+ &["\u{27}\u{308}", "\u{61}", "\u{2c}"]), ("\u{27}\u{31}\u{3a}", &["\u{27}", "\u{31}",
+ "\u{3a}"]), ("\u{27}\u{308}\u{31}\u{3a}", &["\u{27}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{27}\u{31}\u{27}", &["\u{27}", "\u{31}", "\u{27}"]), ("\u{27}\u{308}\u{31}\u{27}",
+ &["\u{27}\u{308}", "\u{31}", "\u{27}"]), ("\u{27}\u{31}\u{2c}", &["\u{27}", "\u{31}",
+ "\u{2c}"]), ("\u{27}\u{308}\u{31}\u{2c}", &["\u{27}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{27}\u{31}\u{2e}\u{2060}", &["\u{27}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{27}\u{308}\u{31}\u{2e}\u{2060}", &["\u{27}\u{308}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{231a}\u{1}", &["\u{231a}", "\u{1}"]), ("\u{231a}\u{308}\u{1}", &["\u{231a}\u{308}",
+ "\u{1}"]), ("\u{231a}\u{d}", &["\u{231a}", "\u{d}"]), ("\u{231a}\u{308}\u{d}",
+ &["\u{231a}\u{308}", "\u{d}"]), ("\u{231a}\u{a}", &["\u{231a}", "\u{a}"]),
+ ("\u{231a}\u{308}\u{a}", &["\u{231a}\u{308}", "\u{a}"]), ("\u{231a}\u{b}", &["\u{231a}",
+ "\u{b}"]), ("\u{231a}\u{308}\u{b}", &["\u{231a}\u{308}", "\u{b}"]), ("\u{231a}\u{3031}",
+ &["\u{231a}", "\u{3031}"]), ("\u{231a}\u{308}\u{3031}", &["\u{231a}\u{308}", "\u{3031}"]),
+ ("\u{231a}\u{41}", &["\u{231a}", "\u{41}"]), ("\u{231a}\u{308}\u{41}", &["\u{231a}\u{308}",
+ "\u{41}"]), ("\u{231a}\u{3a}", &["\u{231a}", "\u{3a}"]), ("\u{231a}\u{308}\u{3a}",
+ &["\u{231a}\u{308}", "\u{3a}"]), ("\u{231a}\u{2c}", &["\u{231a}", "\u{2c}"]),
+ ("\u{231a}\u{308}\u{2c}", &["\u{231a}\u{308}", "\u{2c}"]), ("\u{231a}\u{2e}", &["\u{231a}",
+ "\u{2e}"]), ("\u{231a}\u{308}\u{2e}", &["\u{231a}\u{308}", "\u{2e}"]), ("\u{231a}\u{30}",
+ &["\u{231a}", "\u{30}"]), ("\u{231a}\u{308}\u{30}", &["\u{231a}\u{308}", "\u{30}"]),
+ ("\u{231a}\u{5f}", &["\u{231a}", "\u{5f}"]), ("\u{231a}\u{308}\u{5f}", &["\u{231a}\u{308}",
+ "\u{5f}"]), ("\u{231a}\u{1f1e6}", &["\u{231a}", "\u{1f1e6}"]), ("\u{231a}\u{308}\u{1f1e6}",
+ &["\u{231a}\u{308}", "\u{1f1e6}"]), ("\u{231a}\u{5d0}", &["\u{231a}", "\u{5d0}"]),
+ ("\u{231a}\u{308}\u{5d0}", &["\u{231a}\u{308}", "\u{5d0}"]), ("\u{231a}\u{22}",
+ &["\u{231a}", "\u{22}"]), ("\u{231a}\u{308}\u{22}", &["\u{231a}\u{308}", "\u{22}"]),
+ ("\u{231a}\u{27}", &["\u{231a}", "\u{27}"]), ("\u{231a}\u{308}\u{27}", &["\u{231a}\u{308}",
+ "\u{27}"]), ("\u{231a}\u{231a}", &["\u{231a}", "\u{231a}"]), ("\u{231a}\u{308}\u{231a}",
+ &["\u{231a}\u{308}", "\u{231a}"]), ("\u{231a}\u{20}", &["\u{231a}", "\u{20}"]),
+ ("\u{231a}\u{308}\u{20}", &["\u{231a}\u{308}", "\u{20}"]), ("\u{231a}\u{ad}",
+ &["\u{231a}\u{ad}"]), ("\u{231a}\u{308}\u{ad}", &["\u{231a}\u{308}\u{ad}"]),
+ ("\u{231a}\u{300}", &["\u{231a}\u{300}"]), ("\u{231a}\u{308}\u{300}",
+ &["\u{231a}\u{308}\u{300}"]), ("\u{231a}\u{200d}", &["\u{231a}\u{200d}"]),
+ ("\u{231a}\u{308}\u{200d}", &["\u{231a}\u{308}\u{200d}"]), ("\u{231a}\u{61}\u{2060}",
+ &["\u{231a}", "\u{61}\u{2060}"]), ("\u{231a}\u{308}\u{61}\u{2060}", &["\u{231a}\u{308}",
+ "\u{61}\u{2060}"]), ("\u{231a}\u{61}\u{3a}", &["\u{231a}", "\u{61}", "\u{3a}"]),
+ ("\u{231a}\u{308}\u{61}\u{3a}", &["\u{231a}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{231a}\u{61}\u{27}", &["\u{231a}", "\u{61}", "\u{27}"]), ("\u{231a}\u{308}\u{61}\u{27}",
+ &["\u{231a}\u{308}", "\u{61}", "\u{27}"]), ("\u{231a}\u{61}\u{27}\u{2060}", &["\u{231a}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{231a}\u{308}\u{61}\u{27}\u{2060}", &["\u{231a}\u{308}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{231a}\u{61}\u{2c}", &["\u{231a}", "\u{61}", "\u{2c}"]),
+ ("\u{231a}\u{308}\u{61}\u{2c}", &["\u{231a}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{231a}\u{31}\u{3a}", &["\u{231a}", "\u{31}", "\u{3a}"]), ("\u{231a}\u{308}\u{31}\u{3a}",
+ &["\u{231a}\u{308}", "\u{31}", "\u{3a}"]), ("\u{231a}\u{31}\u{27}", &["\u{231a}", "\u{31}",
+ "\u{27}"]), ("\u{231a}\u{308}\u{31}\u{27}", &["\u{231a}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{231a}\u{31}\u{2c}", &["\u{231a}", "\u{31}", "\u{2c}"]), ("\u{231a}\u{308}\u{31}\u{2c}",
+ &["\u{231a}\u{308}", "\u{31}", "\u{2c}"]), ("\u{231a}\u{31}\u{2e}\u{2060}", &["\u{231a}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{231a}\u{308}\u{31}\u{2e}\u{2060}", &["\u{231a}\u{308}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{20}\u{1}", &["\u{20}", "\u{1}"]), ("\u{20}\u{308}\u{1}",
+ &["\u{20}\u{308}", "\u{1}"]), ("\u{20}\u{d}", &["\u{20}", "\u{d}"]), ("\u{20}\u{308}\u{d}",
+ &["\u{20}\u{308}", "\u{d}"]), ("\u{20}\u{a}", &["\u{20}", "\u{a}"]), ("\u{20}\u{308}\u{a}",
+ &["\u{20}\u{308}", "\u{a}"]), ("\u{20}\u{b}", &["\u{20}", "\u{b}"]), ("\u{20}\u{308}\u{b}",
+ &["\u{20}\u{308}", "\u{b}"]), ("\u{20}\u{3031}", &["\u{20}", "\u{3031}"]),
+ ("\u{20}\u{308}\u{3031}", &["\u{20}\u{308}", "\u{3031}"]), ("\u{20}\u{41}", &["\u{20}",
+ "\u{41}"]), ("\u{20}\u{308}\u{41}", &["\u{20}\u{308}", "\u{41}"]), ("\u{20}\u{3a}",
+ &["\u{20}", "\u{3a}"]), ("\u{20}\u{308}\u{3a}", &["\u{20}\u{308}", "\u{3a}"]),
+ ("\u{20}\u{2c}", &["\u{20}", "\u{2c}"]), ("\u{20}\u{308}\u{2c}", &["\u{20}\u{308}",
+ "\u{2c}"]), ("\u{20}\u{2e}", &["\u{20}", "\u{2e}"]), ("\u{20}\u{308}\u{2e}",
+ &["\u{20}\u{308}", "\u{2e}"]), ("\u{20}\u{30}", &["\u{20}", "\u{30}"]),
+ ("\u{20}\u{308}\u{30}", &["\u{20}\u{308}", "\u{30}"]), ("\u{20}\u{5f}", &["\u{20}",
+ "\u{5f}"]), ("\u{20}\u{308}\u{5f}", &["\u{20}\u{308}", "\u{5f}"]), ("\u{20}\u{1f1e6}",
+ &["\u{20}", "\u{1f1e6}"]), ("\u{20}\u{308}\u{1f1e6}", &["\u{20}\u{308}", "\u{1f1e6}"]),
+ ("\u{20}\u{5d0}", &["\u{20}", "\u{5d0}"]), ("\u{20}\u{308}\u{5d0}", &["\u{20}\u{308}",
+ "\u{5d0}"]), ("\u{20}\u{22}", &["\u{20}", "\u{22}"]), ("\u{20}\u{308}\u{22}",
+ &["\u{20}\u{308}", "\u{22}"]), ("\u{20}\u{27}", &["\u{20}", "\u{27}"]),
+ ("\u{20}\u{308}\u{27}", &["\u{20}\u{308}", "\u{27}"]), ("\u{20}\u{231a}", &["\u{20}",
+ "\u{231a}"]), ("\u{20}\u{308}\u{231a}", &["\u{20}\u{308}", "\u{231a}"]), ("\u{20}\u{20}",
+ &["\u{20}\u{20}"]), ("\u{20}\u{308}\u{20}", &["\u{20}\u{308}", "\u{20}"]), ("\u{20}\u{ad}",
+ &["\u{20}\u{ad}"]), ("\u{20}\u{308}\u{ad}", &["\u{20}\u{308}\u{ad}"]), ("\u{20}\u{300}",
+ &["\u{20}\u{300}"]), ("\u{20}\u{308}\u{300}", &["\u{20}\u{308}\u{300}"]), ("\u{20}\u{200d}",
+ &["\u{20}\u{200d}"]), ("\u{20}\u{308}\u{200d}", &["\u{20}\u{308}\u{200d}"]),
+ ("\u{20}\u{61}\u{2060}", &["\u{20}", "\u{61}\u{2060}"]), ("\u{20}\u{308}\u{61}\u{2060}",
+ &["\u{20}\u{308}", "\u{61}\u{2060}"]), ("\u{20}\u{61}\u{3a}", &["\u{20}", "\u{61}",
+ "\u{3a}"]), ("\u{20}\u{308}\u{61}\u{3a}", &["\u{20}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{20}\u{61}\u{27}", &["\u{20}", "\u{61}", "\u{27}"]), ("\u{20}\u{308}\u{61}\u{27}",
+ &["\u{20}\u{308}", "\u{61}", "\u{27}"]), ("\u{20}\u{61}\u{27}\u{2060}", &["\u{20}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{20}\u{308}\u{61}\u{27}\u{2060}", &["\u{20}\u{308}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{20}\u{61}\u{2c}", &["\u{20}", "\u{61}", "\u{2c}"]),
+ ("\u{20}\u{308}\u{61}\u{2c}", &["\u{20}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{20}\u{31}\u{3a}", &["\u{20}", "\u{31}", "\u{3a}"]), ("\u{20}\u{308}\u{31}\u{3a}",
+ &["\u{20}\u{308}", "\u{31}", "\u{3a}"]), ("\u{20}\u{31}\u{27}", &["\u{20}", "\u{31}",
+ "\u{27}"]), ("\u{20}\u{308}\u{31}\u{27}", &["\u{20}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{20}\u{31}\u{2c}", &["\u{20}", "\u{31}", "\u{2c}"]), ("\u{20}\u{308}\u{31}\u{2c}",
+ &["\u{20}\u{308}", "\u{31}", "\u{2c}"]), ("\u{20}\u{31}\u{2e}\u{2060}", &["\u{20}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{20}\u{308}\u{31}\u{2e}\u{2060}", &["\u{20}\u{308}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{ad}\u{1}", &["\u{ad}", "\u{1}"]), ("\u{ad}\u{308}\u{1}",
+ &["\u{ad}\u{308}", "\u{1}"]), ("\u{ad}\u{d}", &["\u{ad}", "\u{d}"]), ("\u{ad}\u{308}\u{d}",
+ &["\u{ad}\u{308}", "\u{d}"]), ("\u{ad}\u{a}", &["\u{ad}", "\u{a}"]), ("\u{ad}\u{308}\u{a}",
+ &["\u{ad}\u{308}", "\u{a}"]), ("\u{ad}\u{b}", &["\u{ad}", "\u{b}"]), ("\u{ad}\u{308}\u{b}",
+ &["\u{ad}\u{308}", "\u{b}"]), ("\u{ad}\u{3031}", &["\u{ad}", "\u{3031}"]),
+ ("\u{ad}\u{308}\u{3031}", &["\u{ad}\u{308}", "\u{3031}"]), ("\u{ad}\u{41}", &["\u{ad}",
+ "\u{41}"]), ("\u{ad}\u{308}\u{41}", &["\u{ad}\u{308}", "\u{41}"]), ("\u{ad}\u{3a}",
+ &["\u{ad}", "\u{3a}"]), ("\u{ad}\u{308}\u{3a}", &["\u{ad}\u{308}", "\u{3a}"]),
+ ("\u{ad}\u{2c}", &["\u{ad}", "\u{2c}"]), ("\u{ad}\u{308}\u{2c}", &["\u{ad}\u{308}",
+ "\u{2c}"]), ("\u{ad}\u{2e}", &["\u{ad}", "\u{2e}"]), ("\u{ad}\u{308}\u{2e}",
+ &["\u{ad}\u{308}", "\u{2e}"]), ("\u{ad}\u{30}", &["\u{ad}", "\u{30}"]),
+ ("\u{ad}\u{308}\u{30}", &["\u{ad}\u{308}", "\u{30}"]), ("\u{ad}\u{5f}", &["\u{ad}",
+ "\u{5f}"]), ("\u{ad}\u{308}\u{5f}", &["\u{ad}\u{308}", "\u{5f}"]), ("\u{ad}\u{1f1e6}",
+ &["\u{ad}", "\u{1f1e6}"]), ("\u{ad}\u{308}\u{1f1e6}", &["\u{ad}\u{308}", "\u{1f1e6}"]),
+ ("\u{ad}\u{5d0}", &["\u{ad}", "\u{5d0}"]), ("\u{ad}\u{308}\u{5d0}", &["\u{ad}\u{308}",
+ "\u{5d0}"]), ("\u{ad}\u{22}", &["\u{ad}", "\u{22}"]), ("\u{ad}\u{308}\u{22}",
+ &["\u{ad}\u{308}", "\u{22}"]), ("\u{ad}\u{27}", &["\u{ad}", "\u{27}"]),
+ ("\u{ad}\u{308}\u{27}", &["\u{ad}\u{308}", "\u{27}"]), ("\u{ad}\u{231a}", &["\u{ad}",
+ "\u{231a}"]), ("\u{ad}\u{308}\u{231a}", &["\u{ad}\u{308}", "\u{231a}"]), ("\u{ad}\u{20}",
+ &["\u{ad}", "\u{20}"]), ("\u{ad}\u{308}\u{20}", &["\u{ad}\u{308}", "\u{20}"]),
+ ("\u{ad}\u{ad}", &["\u{ad}\u{ad}"]), ("\u{ad}\u{308}\u{ad}", &["\u{ad}\u{308}\u{ad}"]),
+ ("\u{ad}\u{300}", &["\u{ad}\u{300}"]), ("\u{ad}\u{308}\u{300}", &["\u{ad}\u{308}\u{300}"]),
+ ("\u{ad}\u{200d}", &["\u{ad}\u{200d}"]), ("\u{ad}\u{308}\u{200d}",
+ &["\u{ad}\u{308}\u{200d}"]), ("\u{ad}\u{61}\u{2060}", &["\u{ad}", "\u{61}\u{2060}"]),
+ ("\u{ad}\u{308}\u{61}\u{2060}", &["\u{ad}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{ad}\u{61}\u{3a}", &["\u{ad}", "\u{61}", "\u{3a}"]), ("\u{ad}\u{308}\u{61}\u{3a}",
+ &["\u{ad}\u{308}", "\u{61}", "\u{3a}"]), ("\u{ad}\u{61}\u{27}", &["\u{ad}", "\u{61}",
+ "\u{27}"]), ("\u{ad}\u{308}\u{61}\u{27}", &["\u{ad}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{ad}\u{61}\u{27}\u{2060}", &["\u{ad}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{ad}\u{308}\u{61}\u{27}\u{2060}", &["\u{ad}\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{ad}\u{61}\u{2c}", &["\u{ad}", "\u{61}", "\u{2c}"]), ("\u{ad}\u{308}\u{61}\u{2c}",
+ &["\u{ad}\u{308}", "\u{61}", "\u{2c}"]), ("\u{ad}\u{31}\u{3a}", &["\u{ad}", "\u{31}",
+ "\u{3a}"]), ("\u{ad}\u{308}\u{31}\u{3a}", &["\u{ad}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{ad}\u{31}\u{27}", &["\u{ad}", "\u{31}", "\u{27}"]), ("\u{ad}\u{308}\u{31}\u{27}",
+ &["\u{ad}\u{308}", "\u{31}", "\u{27}"]), ("\u{ad}\u{31}\u{2c}", &["\u{ad}", "\u{31}",
+ "\u{2c}"]), ("\u{ad}\u{308}\u{31}\u{2c}", &["\u{ad}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{ad}\u{31}\u{2e}\u{2060}", &["\u{ad}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{ad}\u{308}\u{31}\u{2e}\u{2060}", &["\u{ad}\u{308}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{300}\u{1}", &["\u{300}", "\u{1}"]), ("\u{300}\u{308}\u{1}", &["\u{300}\u{308}",
+ "\u{1}"]), ("\u{300}\u{d}", &["\u{300}", "\u{d}"]), ("\u{300}\u{308}\u{d}",
+ &["\u{300}\u{308}", "\u{d}"]), ("\u{300}\u{a}", &["\u{300}", "\u{a}"]),
+ ("\u{300}\u{308}\u{a}", &["\u{300}\u{308}", "\u{a}"]), ("\u{300}\u{b}", &["\u{300}",
+ "\u{b}"]), ("\u{300}\u{308}\u{b}", &["\u{300}\u{308}", "\u{b}"]), ("\u{300}\u{3031}",
+ &["\u{300}", "\u{3031}"]), ("\u{300}\u{308}\u{3031}", &["\u{300}\u{308}", "\u{3031}"]),
+ ("\u{300}\u{41}", &["\u{300}", "\u{41}"]), ("\u{300}\u{308}\u{41}", &["\u{300}\u{308}",
+ "\u{41}"]), ("\u{300}\u{3a}", &["\u{300}", "\u{3a}"]), ("\u{300}\u{308}\u{3a}",
+ &["\u{300}\u{308}", "\u{3a}"]), ("\u{300}\u{2c}", &["\u{300}", "\u{2c}"]),
+ ("\u{300}\u{308}\u{2c}", &["\u{300}\u{308}", "\u{2c}"]), ("\u{300}\u{2e}", &["\u{300}",
+ "\u{2e}"]), ("\u{300}\u{308}\u{2e}", &["\u{300}\u{308}", "\u{2e}"]), ("\u{300}\u{30}",
+ &["\u{300}", "\u{30}"]), ("\u{300}\u{308}\u{30}", &["\u{300}\u{308}", "\u{30}"]),
+ ("\u{300}\u{5f}", &["\u{300}", "\u{5f}"]), ("\u{300}\u{308}\u{5f}", &["\u{300}\u{308}",
+ "\u{5f}"]), ("\u{300}\u{1f1e6}", &["\u{300}", "\u{1f1e6}"]), ("\u{300}\u{308}\u{1f1e6}",
+ &["\u{300}\u{308}", "\u{1f1e6}"]), ("\u{300}\u{5d0}", &["\u{300}", "\u{5d0}"]),
+ ("\u{300}\u{308}\u{5d0}", &["\u{300}\u{308}", "\u{5d0}"]), ("\u{300}\u{22}", &["\u{300}",
+ "\u{22}"]), ("\u{300}\u{308}\u{22}", &["\u{300}\u{308}", "\u{22}"]), ("\u{300}\u{27}",
+ &["\u{300}", "\u{27}"]), ("\u{300}\u{308}\u{27}", &["\u{300}\u{308}", "\u{27}"]),
+ ("\u{300}\u{231a}", &["\u{300}", "\u{231a}"]), ("\u{300}\u{308}\u{231a}",
+ &["\u{300}\u{308}", "\u{231a}"]), ("\u{300}\u{20}", &["\u{300}", "\u{20}"]),
+ ("\u{300}\u{308}\u{20}", &["\u{300}\u{308}", "\u{20}"]), ("\u{300}\u{ad}",
+ &["\u{300}\u{ad}"]), ("\u{300}\u{308}\u{ad}", &["\u{300}\u{308}\u{ad}"]), ("\u{300}\u{300}",
+ &["\u{300}\u{300}"]), ("\u{300}\u{308}\u{300}", &["\u{300}\u{308}\u{300}"]),
+ ("\u{300}\u{200d}", &["\u{300}\u{200d}"]), ("\u{300}\u{308}\u{200d}",
+ &["\u{300}\u{308}\u{200d}"]), ("\u{300}\u{61}\u{2060}", &["\u{300}", "\u{61}\u{2060}"]),
+ ("\u{300}\u{308}\u{61}\u{2060}", &["\u{300}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{300}\u{61}\u{3a}", &["\u{300}", "\u{61}", "\u{3a}"]), ("\u{300}\u{308}\u{61}\u{3a}",
+ &["\u{300}\u{308}", "\u{61}", "\u{3a}"]), ("\u{300}\u{61}\u{27}", &["\u{300}", "\u{61}",
+ "\u{27}"]), ("\u{300}\u{308}\u{61}\u{27}", &["\u{300}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{300}\u{61}\u{27}\u{2060}", &["\u{300}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{300}\u{308}\u{61}\u{27}\u{2060}", &["\u{300}\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{300}\u{61}\u{2c}", &["\u{300}", "\u{61}", "\u{2c}"]), ("\u{300}\u{308}\u{61}\u{2c}",
+ &["\u{300}\u{308}", "\u{61}", "\u{2c}"]), ("\u{300}\u{31}\u{3a}", &["\u{300}", "\u{31}",
+ "\u{3a}"]), ("\u{300}\u{308}\u{31}\u{3a}", &["\u{300}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{300}\u{31}\u{27}", &["\u{300}", "\u{31}", "\u{27}"]), ("\u{300}\u{308}\u{31}\u{27}",
+ &["\u{300}\u{308}", "\u{31}", "\u{27}"]), ("\u{300}\u{31}\u{2c}", &["\u{300}", "\u{31}",
+ "\u{2c}"]), ("\u{300}\u{308}\u{31}\u{2c}", &["\u{300}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{300}\u{31}\u{2e}\u{2060}", &["\u{300}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{300}\u{308}\u{31}\u{2e}\u{2060}", &["\u{300}\u{308}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{200d}\u{1}", &["\u{200d}", "\u{1}"]), ("\u{200d}\u{308}\u{1}", &["\u{200d}\u{308}",
+ "\u{1}"]), ("\u{200d}\u{d}", &["\u{200d}", "\u{d}"]), ("\u{200d}\u{308}\u{d}",
+ &["\u{200d}\u{308}", "\u{d}"]), ("\u{200d}\u{a}", &["\u{200d}", "\u{a}"]),
+ ("\u{200d}\u{308}\u{a}", &["\u{200d}\u{308}", "\u{a}"]), ("\u{200d}\u{b}", &["\u{200d}",
+ "\u{b}"]), ("\u{200d}\u{308}\u{b}", &["\u{200d}\u{308}", "\u{b}"]), ("\u{200d}\u{3031}",
+ &["\u{200d}", "\u{3031}"]), ("\u{200d}\u{308}\u{3031}", &["\u{200d}\u{308}", "\u{3031}"]),
+ ("\u{200d}\u{41}", &["\u{200d}", "\u{41}"]), ("\u{200d}\u{308}\u{41}", &["\u{200d}\u{308}",
+ "\u{41}"]), ("\u{200d}\u{3a}", &["\u{200d}", "\u{3a}"]), ("\u{200d}\u{308}\u{3a}",
+ &["\u{200d}\u{308}", "\u{3a}"]), ("\u{200d}\u{2c}", &["\u{200d}", "\u{2c}"]),
+ ("\u{200d}\u{308}\u{2c}", &["\u{200d}\u{308}", "\u{2c}"]), ("\u{200d}\u{2e}", &["\u{200d}",
+ "\u{2e}"]), ("\u{200d}\u{308}\u{2e}", &["\u{200d}\u{308}", "\u{2e}"]), ("\u{200d}\u{30}",
+ &["\u{200d}", "\u{30}"]), ("\u{200d}\u{308}\u{30}", &["\u{200d}\u{308}", "\u{30}"]),
+ ("\u{200d}\u{5f}", &["\u{200d}", "\u{5f}"]), ("\u{200d}\u{308}\u{5f}", &["\u{200d}\u{308}",
+ "\u{5f}"]), ("\u{200d}\u{1f1e6}", &["\u{200d}", "\u{1f1e6}"]), ("\u{200d}\u{308}\u{1f1e6}",
+ &["\u{200d}\u{308}", "\u{1f1e6}"]), ("\u{200d}\u{5d0}", &["\u{200d}", "\u{5d0}"]),
+ ("\u{200d}\u{308}\u{5d0}", &["\u{200d}\u{308}", "\u{5d0}"]), ("\u{200d}\u{22}",
+ &["\u{200d}", "\u{22}"]), ("\u{200d}\u{308}\u{22}", &["\u{200d}\u{308}", "\u{22}"]),
+ ("\u{200d}\u{27}", &["\u{200d}", "\u{27}"]), ("\u{200d}\u{308}\u{27}", &["\u{200d}\u{308}",
+ "\u{27}"]), ("\u{200d}\u{231a}", &["\u{200d}\u{231a}"]), ("\u{200d}\u{308}\u{231a}",
+ &["\u{200d}\u{308}", "\u{231a}"]), ("\u{200d}\u{20}", &["\u{200d}", "\u{20}"]),
+ ("\u{200d}\u{308}\u{20}", &["\u{200d}\u{308}", "\u{20}"]), ("\u{200d}\u{ad}",
+ &["\u{200d}\u{ad}"]), ("\u{200d}\u{308}\u{ad}", &["\u{200d}\u{308}\u{ad}"]),
+ ("\u{200d}\u{300}", &["\u{200d}\u{300}"]), ("\u{200d}\u{308}\u{300}",
+ &["\u{200d}\u{308}\u{300}"]), ("\u{200d}\u{200d}", &["\u{200d}\u{200d}"]),
+ ("\u{200d}\u{308}\u{200d}", &["\u{200d}\u{308}\u{200d}"]), ("\u{200d}\u{61}\u{2060}",
+ &["\u{200d}", "\u{61}\u{2060}"]), ("\u{200d}\u{308}\u{61}\u{2060}", &["\u{200d}\u{308}",
+ "\u{61}\u{2060}"]), ("\u{200d}\u{61}\u{3a}", &["\u{200d}", "\u{61}", "\u{3a}"]),
+ ("\u{200d}\u{308}\u{61}\u{3a}", &["\u{200d}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{200d}\u{61}\u{27}", &["\u{200d}", "\u{61}", "\u{27}"]), ("\u{200d}\u{308}\u{61}\u{27}",
+ &["\u{200d}\u{308}", "\u{61}", "\u{27}"]), ("\u{200d}\u{61}\u{27}\u{2060}", &["\u{200d}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{200d}\u{308}\u{61}\u{27}\u{2060}", &["\u{200d}\u{308}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{200d}\u{61}\u{2c}", &["\u{200d}", "\u{61}", "\u{2c}"]),
+ ("\u{200d}\u{308}\u{61}\u{2c}", &["\u{200d}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{200d}\u{31}\u{3a}", &["\u{200d}", "\u{31}", "\u{3a}"]), ("\u{200d}\u{308}\u{31}\u{3a}",
+ &["\u{200d}\u{308}", "\u{31}", "\u{3a}"]), ("\u{200d}\u{31}\u{27}", &["\u{200d}", "\u{31}",
+ "\u{27}"]), ("\u{200d}\u{308}\u{31}\u{27}", &["\u{200d}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{200d}\u{31}\u{2c}", &["\u{200d}", "\u{31}", "\u{2c}"]), ("\u{200d}\u{308}\u{31}\u{2c}",
+ &["\u{200d}\u{308}", "\u{31}", "\u{2c}"]), ("\u{200d}\u{31}\u{2e}\u{2060}", &["\u{200d}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{200d}\u{308}\u{31}\u{2e}\u{2060}", &["\u{200d}\u{308}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{61}\u{2060}\u{1}", &["\u{61}\u{2060}", "\u{1}"]),
+ ("\u{61}\u{2060}\u{308}\u{1}", &["\u{61}\u{2060}\u{308}", "\u{1}"]), ("\u{61}\u{2060}\u{d}",
+ &["\u{61}\u{2060}", "\u{d}"]), ("\u{61}\u{2060}\u{308}\u{d}", &["\u{61}\u{2060}\u{308}",
+ "\u{d}"]), ("\u{61}\u{2060}\u{a}", &["\u{61}\u{2060}", "\u{a}"]),
+ ("\u{61}\u{2060}\u{308}\u{a}", &["\u{61}\u{2060}\u{308}", "\u{a}"]), ("\u{61}\u{2060}\u{b}",
+ &["\u{61}\u{2060}", "\u{b}"]), ("\u{61}\u{2060}\u{308}\u{b}", &["\u{61}\u{2060}\u{308}",
+ "\u{b}"]), ("\u{61}\u{2060}\u{3031}", &["\u{61}\u{2060}", "\u{3031}"]),
+ ("\u{61}\u{2060}\u{308}\u{3031}", &["\u{61}\u{2060}\u{308}", "\u{3031}"]),
+ ("\u{61}\u{2060}\u{41}", &["\u{61}\u{2060}\u{41}"]), ("\u{61}\u{2060}\u{308}\u{41}",
+ &["\u{61}\u{2060}\u{308}\u{41}"]), ("\u{61}\u{2060}\u{3a}", &["\u{61}\u{2060}", "\u{3a}"]),
+ ("\u{61}\u{2060}\u{308}\u{3a}", &["\u{61}\u{2060}\u{308}", "\u{3a}"]),
+ ("\u{61}\u{2060}\u{2c}", &["\u{61}\u{2060}", "\u{2c}"]), ("\u{61}\u{2060}\u{308}\u{2c}",
+ &["\u{61}\u{2060}\u{308}", "\u{2c}"]), ("\u{61}\u{2060}\u{2e}", &["\u{61}\u{2060}",
+ "\u{2e}"]), ("\u{61}\u{2060}\u{308}\u{2e}", &["\u{61}\u{2060}\u{308}", "\u{2e}"]),
+ ("\u{61}\u{2060}\u{30}", &["\u{61}\u{2060}\u{30}"]), ("\u{61}\u{2060}\u{308}\u{30}",
+ &["\u{61}\u{2060}\u{308}\u{30}"]), ("\u{61}\u{2060}\u{5f}", &["\u{61}\u{2060}\u{5f}"]),
+ ("\u{61}\u{2060}\u{308}\u{5f}", &["\u{61}\u{2060}\u{308}\u{5f}"]),
+ ("\u{61}\u{2060}\u{1f1e6}", &["\u{61}\u{2060}", "\u{1f1e6}"]),
+ ("\u{61}\u{2060}\u{308}\u{1f1e6}", &["\u{61}\u{2060}\u{308}", "\u{1f1e6}"]),
+ ("\u{61}\u{2060}\u{5d0}", &["\u{61}\u{2060}\u{5d0}"]), ("\u{61}\u{2060}\u{308}\u{5d0}",
+ &["\u{61}\u{2060}\u{308}\u{5d0}"]), ("\u{61}\u{2060}\u{22}", &["\u{61}\u{2060}", "\u{22}"]),
+ ("\u{61}\u{2060}\u{308}\u{22}", &["\u{61}\u{2060}\u{308}", "\u{22}"]),
+ ("\u{61}\u{2060}\u{27}", &["\u{61}\u{2060}", "\u{27}"]), ("\u{61}\u{2060}\u{308}\u{27}",
+ &["\u{61}\u{2060}\u{308}", "\u{27}"]), ("\u{61}\u{2060}\u{231a}", &["\u{61}\u{2060}",
+ "\u{231a}"]), ("\u{61}\u{2060}\u{308}\u{231a}", &["\u{61}\u{2060}\u{308}", "\u{231a}"]),
+ ("\u{61}\u{2060}\u{20}", &["\u{61}\u{2060}", "\u{20}"]), ("\u{61}\u{2060}\u{308}\u{20}",
+ &["\u{61}\u{2060}\u{308}", "\u{20}"]), ("\u{61}\u{2060}\u{ad}", &["\u{61}\u{2060}\u{ad}"]),
+ ("\u{61}\u{2060}\u{308}\u{ad}", &["\u{61}\u{2060}\u{308}\u{ad}"]), ("\u{61}\u{2060}\u{300}",
+ &["\u{61}\u{2060}\u{300}"]), ("\u{61}\u{2060}\u{308}\u{300}",
+ &["\u{61}\u{2060}\u{308}\u{300}"]), ("\u{61}\u{2060}\u{200d}", &["\u{61}\u{2060}\u{200d}"]),
+ ("\u{61}\u{2060}\u{308}\u{200d}", &["\u{61}\u{2060}\u{308}\u{200d}"]),
+ ("\u{61}\u{2060}\u{61}\u{2060}", &["\u{61}\u{2060}\u{61}\u{2060}"]),
+ ("\u{61}\u{2060}\u{308}\u{61}\u{2060}", &["\u{61}\u{2060}\u{308}\u{61}\u{2060}"]),
+ ("\u{61}\u{2060}\u{61}\u{3a}", &["\u{61}\u{2060}\u{61}", "\u{3a}"]),
+ ("\u{61}\u{2060}\u{308}\u{61}\u{3a}", &["\u{61}\u{2060}\u{308}\u{61}", "\u{3a}"]),
+ ("\u{61}\u{2060}\u{61}\u{27}", &["\u{61}\u{2060}\u{61}", "\u{27}"]),
+ ("\u{61}\u{2060}\u{308}\u{61}\u{27}", &["\u{61}\u{2060}\u{308}\u{61}", "\u{27}"]),
+ ("\u{61}\u{2060}\u{61}\u{27}\u{2060}", &["\u{61}\u{2060}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{61}\u{2060}\u{308}\u{61}\u{27}\u{2060}", &["\u{61}\u{2060}\u{308}\u{61}",
+ "\u{27}\u{2060}"]), ("\u{61}\u{2060}\u{61}\u{2c}", &["\u{61}\u{2060}\u{61}", "\u{2c}"]),
+ ("\u{61}\u{2060}\u{308}\u{61}\u{2c}", &["\u{61}\u{2060}\u{308}\u{61}", "\u{2c}"]),
+ ("\u{61}\u{2060}\u{31}\u{3a}", &["\u{61}\u{2060}\u{31}", "\u{3a}"]),
+ ("\u{61}\u{2060}\u{308}\u{31}\u{3a}", &["\u{61}\u{2060}\u{308}\u{31}", "\u{3a}"]),
+ ("\u{61}\u{2060}\u{31}\u{27}", &["\u{61}\u{2060}\u{31}", "\u{27}"]),
+ ("\u{61}\u{2060}\u{308}\u{31}\u{27}", &["\u{61}\u{2060}\u{308}\u{31}", "\u{27}"]),
+ ("\u{61}\u{2060}\u{31}\u{2c}", &["\u{61}\u{2060}\u{31}", "\u{2c}"]),
+ ("\u{61}\u{2060}\u{308}\u{31}\u{2c}", &["\u{61}\u{2060}\u{308}\u{31}", "\u{2c}"]),
+ ("\u{61}\u{2060}\u{31}\u{2e}\u{2060}", &["\u{61}\u{2060}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{61}\u{2060}\u{308}\u{31}\u{2e}\u{2060}", &["\u{61}\u{2060}\u{308}\u{31}",
+ "\u{2e}\u{2060}"]), ("\u{61}\u{3a}\u{1}", &["\u{61}", "\u{3a}", "\u{1}"]),
+ ("\u{61}\u{3a}\u{308}\u{1}", &["\u{61}", "\u{3a}\u{308}", "\u{1}"]), ("\u{61}\u{3a}\u{d}",
+ &["\u{61}", "\u{3a}", "\u{d}"]), ("\u{61}\u{3a}\u{308}\u{d}", &["\u{61}", "\u{3a}\u{308}",
+ "\u{d}"]), ("\u{61}\u{3a}\u{a}", &["\u{61}", "\u{3a}", "\u{a}"]),
+ ("\u{61}\u{3a}\u{308}\u{a}", &["\u{61}", "\u{3a}\u{308}", "\u{a}"]), ("\u{61}\u{3a}\u{b}",
+ &["\u{61}", "\u{3a}", "\u{b}"]), ("\u{61}\u{3a}\u{308}\u{b}", &["\u{61}", "\u{3a}\u{308}",
+ "\u{b}"]), ("\u{61}\u{3a}\u{3031}", &["\u{61}", "\u{3a}", "\u{3031}"]),
+ ("\u{61}\u{3a}\u{308}\u{3031}", &["\u{61}", "\u{3a}\u{308}", "\u{3031}"]),
+ ("\u{61}\u{3a}\u{41}", &["\u{61}\u{3a}\u{41}"]), ("\u{61}\u{3a}\u{308}\u{41}",
+ &["\u{61}\u{3a}\u{308}\u{41}"]), ("\u{61}\u{3a}\u{3a}", &["\u{61}", "\u{3a}", "\u{3a}"]),
+ ("\u{61}\u{3a}\u{308}\u{3a}", &["\u{61}", "\u{3a}\u{308}", "\u{3a}"]),
+ ("\u{61}\u{3a}\u{2c}", &["\u{61}", "\u{3a}", "\u{2c}"]), ("\u{61}\u{3a}\u{308}\u{2c}",
+ &["\u{61}", "\u{3a}\u{308}", "\u{2c}"]), ("\u{61}\u{3a}\u{2e}", &["\u{61}", "\u{3a}",
+ "\u{2e}"]), ("\u{61}\u{3a}\u{308}\u{2e}", &["\u{61}", "\u{3a}\u{308}", "\u{2e}"]),
+ ("\u{61}\u{3a}\u{30}", &["\u{61}", "\u{3a}", "\u{30}"]), ("\u{61}\u{3a}\u{308}\u{30}",
+ &["\u{61}", "\u{3a}\u{308}", "\u{30}"]), ("\u{61}\u{3a}\u{5f}", &["\u{61}", "\u{3a}",
+ "\u{5f}"]), ("\u{61}\u{3a}\u{308}\u{5f}", &["\u{61}", "\u{3a}\u{308}", "\u{5f}"]),
+ ("\u{61}\u{3a}\u{1f1e6}", &["\u{61}", "\u{3a}", "\u{1f1e6}"]),
+ ("\u{61}\u{3a}\u{308}\u{1f1e6}", &["\u{61}", "\u{3a}\u{308}", "\u{1f1e6}"]),
+ ("\u{61}\u{3a}\u{5d0}", &["\u{61}\u{3a}\u{5d0}"]), ("\u{61}\u{3a}\u{308}\u{5d0}",
+ &["\u{61}\u{3a}\u{308}\u{5d0}"]), ("\u{61}\u{3a}\u{22}", &["\u{61}", "\u{3a}", "\u{22}"]),
+ ("\u{61}\u{3a}\u{308}\u{22}", &["\u{61}", "\u{3a}\u{308}", "\u{22}"]),
+ ("\u{61}\u{3a}\u{27}", &["\u{61}", "\u{3a}", "\u{27}"]), ("\u{61}\u{3a}\u{308}\u{27}",
+ &["\u{61}", "\u{3a}\u{308}", "\u{27}"]), ("\u{61}\u{3a}\u{231a}", &["\u{61}", "\u{3a}",
+ "\u{231a}"]), ("\u{61}\u{3a}\u{308}\u{231a}", &["\u{61}", "\u{3a}\u{308}", "\u{231a}"]),
+ ("\u{61}\u{3a}\u{20}", &["\u{61}", "\u{3a}", "\u{20}"]), ("\u{61}\u{3a}\u{308}\u{20}",
+ &["\u{61}", "\u{3a}\u{308}", "\u{20}"]), ("\u{61}\u{3a}\u{ad}", &["\u{61}",
+ "\u{3a}\u{ad}"]), ("\u{61}\u{3a}\u{308}\u{ad}", &["\u{61}", "\u{3a}\u{308}\u{ad}"]),
+ ("\u{61}\u{3a}\u{300}", &["\u{61}", "\u{3a}\u{300}"]), ("\u{61}\u{3a}\u{308}\u{300}",
+ &["\u{61}", "\u{3a}\u{308}\u{300}"]), ("\u{61}\u{3a}\u{200d}", &["\u{61}",
+ "\u{3a}\u{200d}"]), ("\u{61}\u{3a}\u{308}\u{200d}", &["\u{61}", "\u{3a}\u{308}\u{200d}"]),
+ ("\u{61}\u{3a}\u{61}\u{2060}", &["\u{61}\u{3a}\u{61}\u{2060}"]),
+ ("\u{61}\u{3a}\u{308}\u{61}\u{2060}", &["\u{61}\u{3a}\u{308}\u{61}\u{2060}"]),
+ ("\u{61}\u{3a}\u{61}\u{3a}", &["\u{61}\u{3a}\u{61}", "\u{3a}"]),
+ ("\u{61}\u{3a}\u{308}\u{61}\u{3a}", &["\u{61}\u{3a}\u{308}\u{61}", "\u{3a}"]),
+ ("\u{61}\u{3a}\u{61}\u{27}", &["\u{61}\u{3a}\u{61}", "\u{27}"]),
+ ("\u{61}\u{3a}\u{308}\u{61}\u{27}", &["\u{61}\u{3a}\u{308}\u{61}", "\u{27}"]),
+ ("\u{61}\u{3a}\u{61}\u{27}\u{2060}", &["\u{61}\u{3a}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{61}\u{3a}\u{308}\u{61}\u{27}\u{2060}", &["\u{61}\u{3a}\u{308}\u{61}",
+ "\u{27}\u{2060}"]), ("\u{61}\u{3a}\u{61}\u{2c}", &["\u{61}\u{3a}\u{61}", "\u{2c}"]),
+ ("\u{61}\u{3a}\u{308}\u{61}\u{2c}", &["\u{61}\u{3a}\u{308}\u{61}", "\u{2c}"]),
+ ("\u{61}\u{3a}\u{31}\u{3a}", &["\u{61}", "\u{3a}", "\u{31}", "\u{3a}"]),
+ ("\u{61}\u{3a}\u{308}\u{31}\u{3a}", &["\u{61}", "\u{3a}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{61}\u{3a}\u{31}\u{27}", &["\u{61}", "\u{3a}", "\u{31}", "\u{27}"]),
+ ("\u{61}\u{3a}\u{308}\u{31}\u{27}", &["\u{61}", "\u{3a}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{61}\u{3a}\u{31}\u{2c}", &["\u{61}", "\u{3a}", "\u{31}", "\u{2c}"]),
+ ("\u{61}\u{3a}\u{308}\u{31}\u{2c}", &["\u{61}", "\u{3a}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{61}\u{3a}\u{31}\u{2e}\u{2060}", &["\u{61}", "\u{3a}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{61}\u{3a}\u{308}\u{31}\u{2e}\u{2060}", &["\u{61}", "\u{3a}\u{308}", "\u{31}",
+ "\u{2e}\u{2060}"]), ("\u{61}\u{27}\u{1}", &["\u{61}", "\u{27}", "\u{1}"]),
+ ("\u{61}\u{27}\u{308}\u{1}", &["\u{61}", "\u{27}\u{308}", "\u{1}"]), ("\u{61}\u{27}\u{d}",
+ &["\u{61}", "\u{27}", "\u{d}"]), ("\u{61}\u{27}\u{308}\u{d}", &["\u{61}", "\u{27}\u{308}",
+ "\u{d}"]), ("\u{61}\u{27}\u{a}", &["\u{61}", "\u{27}", "\u{a}"]),
+ ("\u{61}\u{27}\u{308}\u{a}", &["\u{61}", "\u{27}\u{308}", "\u{a}"]), ("\u{61}\u{27}\u{b}",
+ &["\u{61}", "\u{27}", "\u{b}"]), ("\u{61}\u{27}\u{308}\u{b}", &["\u{61}", "\u{27}\u{308}",
+ "\u{b}"]), ("\u{61}\u{27}\u{3031}", &["\u{61}", "\u{27}", "\u{3031}"]),
+ ("\u{61}\u{27}\u{308}\u{3031}", &["\u{61}", "\u{27}\u{308}", "\u{3031}"]),
+ ("\u{61}\u{27}\u{41}", &["\u{61}\u{27}\u{41}"]), ("\u{61}\u{27}\u{308}\u{41}",
+ &["\u{61}\u{27}\u{308}\u{41}"]), ("\u{61}\u{27}\u{3a}", &["\u{61}", "\u{27}", "\u{3a}"]),
+ ("\u{61}\u{27}\u{308}\u{3a}", &["\u{61}", "\u{27}\u{308}", "\u{3a}"]),
+ ("\u{61}\u{27}\u{2c}", &["\u{61}", "\u{27}", "\u{2c}"]), ("\u{61}\u{27}\u{308}\u{2c}",
+ &["\u{61}", "\u{27}\u{308}", "\u{2c}"]), ("\u{61}\u{27}\u{2e}", &["\u{61}", "\u{27}",
+ "\u{2e}"]), ("\u{61}\u{27}\u{308}\u{2e}", &["\u{61}", "\u{27}\u{308}", "\u{2e}"]),
+ ("\u{61}\u{27}\u{30}", &["\u{61}", "\u{27}", "\u{30}"]), ("\u{61}\u{27}\u{308}\u{30}",
+ &["\u{61}", "\u{27}\u{308}", "\u{30}"]), ("\u{61}\u{27}\u{5f}", &["\u{61}", "\u{27}",
+ "\u{5f}"]), ("\u{61}\u{27}\u{308}\u{5f}", &["\u{61}", "\u{27}\u{308}", "\u{5f}"]),
+ ("\u{61}\u{27}\u{1f1e6}", &["\u{61}", "\u{27}", "\u{1f1e6}"]),
+ ("\u{61}\u{27}\u{308}\u{1f1e6}", &["\u{61}", "\u{27}\u{308}", "\u{1f1e6}"]),
+ ("\u{61}\u{27}\u{5d0}", &["\u{61}\u{27}\u{5d0}"]), ("\u{61}\u{27}\u{308}\u{5d0}",
+ &["\u{61}\u{27}\u{308}\u{5d0}"]), ("\u{61}\u{27}\u{22}", &["\u{61}", "\u{27}", "\u{22}"]),
+ ("\u{61}\u{27}\u{308}\u{22}", &["\u{61}", "\u{27}\u{308}", "\u{22}"]),
+ ("\u{61}\u{27}\u{27}", &["\u{61}", "\u{27}", "\u{27}"]), ("\u{61}\u{27}\u{308}\u{27}",
+ &["\u{61}", "\u{27}\u{308}", "\u{27}"]), ("\u{61}\u{27}\u{231a}", &["\u{61}", "\u{27}",
+ "\u{231a}"]), ("\u{61}\u{27}\u{308}\u{231a}", &["\u{61}", "\u{27}\u{308}", "\u{231a}"]),
+ ("\u{61}\u{27}\u{20}", &["\u{61}", "\u{27}", "\u{20}"]), ("\u{61}\u{27}\u{308}\u{20}",
+ &["\u{61}", "\u{27}\u{308}", "\u{20}"]), ("\u{61}\u{27}\u{ad}", &["\u{61}",
+ "\u{27}\u{ad}"]), ("\u{61}\u{27}\u{308}\u{ad}", &["\u{61}", "\u{27}\u{308}\u{ad}"]),
+ ("\u{61}\u{27}\u{300}", &["\u{61}", "\u{27}\u{300}"]), ("\u{61}\u{27}\u{308}\u{300}",
+ &["\u{61}", "\u{27}\u{308}\u{300}"]), ("\u{61}\u{27}\u{200d}", &["\u{61}",
+ "\u{27}\u{200d}"]), ("\u{61}\u{27}\u{308}\u{200d}", &["\u{61}", "\u{27}\u{308}\u{200d}"]),
+ ("\u{61}\u{27}\u{61}\u{2060}", &["\u{61}\u{27}\u{61}\u{2060}"]),
+ ("\u{61}\u{27}\u{308}\u{61}\u{2060}", &["\u{61}\u{27}\u{308}\u{61}\u{2060}"]),
+ ("\u{61}\u{27}\u{61}\u{3a}", &["\u{61}\u{27}\u{61}", "\u{3a}"]),
+ ("\u{61}\u{27}\u{308}\u{61}\u{3a}", &["\u{61}\u{27}\u{308}\u{61}", "\u{3a}"]),
+ ("\u{61}\u{27}\u{61}\u{27}", &["\u{61}\u{27}\u{61}", "\u{27}"]),
+ ("\u{61}\u{27}\u{308}\u{61}\u{27}", &["\u{61}\u{27}\u{308}\u{61}", "\u{27}"]),
+ ("\u{61}\u{27}\u{61}\u{27}\u{2060}", &["\u{61}\u{27}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{61}\u{27}\u{308}\u{61}\u{27}\u{2060}", &["\u{61}\u{27}\u{308}\u{61}",
+ "\u{27}\u{2060}"]), ("\u{61}\u{27}\u{61}\u{2c}", &["\u{61}\u{27}\u{61}", "\u{2c}"]),
+ ("\u{61}\u{27}\u{308}\u{61}\u{2c}", &["\u{61}\u{27}\u{308}\u{61}", "\u{2c}"]),
+ ("\u{61}\u{27}\u{31}\u{3a}", &["\u{61}", "\u{27}", "\u{31}", "\u{3a}"]),
+ ("\u{61}\u{27}\u{308}\u{31}\u{3a}", &["\u{61}", "\u{27}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{61}\u{27}\u{31}\u{27}", &["\u{61}", "\u{27}", "\u{31}", "\u{27}"]),
+ ("\u{61}\u{27}\u{308}\u{31}\u{27}", &["\u{61}", "\u{27}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{61}\u{27}\u{31}\u{2c}", &["\u{61}", "\u{27}", "\u{31}", "\u{2c}"]),
+ ("\u{61}\u{27}\u{308}\u{31}\u{2c}", &["\u{61}", "\u{27}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{61}\u{27}\u{31}\u{2e}\u{2060}", &["\u{61}", "\u{27}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{61}\u{27}\u{308}\u{31}\u{2e}\u{2060}", &["\u{61}", "\u{27}\u{308}", "\u{31}",
+ "\u{2e}\u{2060}"]), ("\u{61}\u{27}\u{2060}\u{1}", &["\u{61}", "\u{27}\u{2060}", "\u{1}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{1}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{1}"]),
+ ("\u{61}\u{27}\u{2060}\u{d}", &["\u{61}", "\u{27}\u{2060}", "\u{d}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{d}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{d}"]),
+ ("\u{61}\u{27}\u{2060}\u{a}", &["\u{61}", "\u{27}\u{2060}", "\u{a}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{a}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{a}"]),
+ ("\u{61}\u{27}\u{2060}\u{b}", &["\u{61}", "\u{27}\u{2060}", "\u{b}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{b}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{b}"]),
+ ("\u{61}\u{27}\u{2060}\u{3031}", &["\u{61}", "\u{27}\u{2060}", "\u{3031}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{3031}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{3031}"]),
+ ("\u{61}\u{27}\u{2060}\u{41}", &["\u{61}\u{27}\u{2060}\u{41}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{41}", &["\u{61}\u{27}\u{2060}\u{308}\u{41}"]),
+ ("\u{61}\u{27}\u{2060}\u{3a}", &["\u{61}", "\u{27}\u{2060}", "\u{3a}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{3a}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{3a}"]),
+ ("\u{61}\u{27}\u{2060}\u{2c}", &["\u{61}", "\u{27}\u{2060}", "\u{2c}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{2c}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{2c}"]),
+ ("\u{61}\u{27}\u{2060}\u{2e}", &["\u{61}", "\u{27}\u{2060}", "\u{2e}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{2e}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{2e}"]),
+ ("\u{61}\u{27}\u{2060}\u{30}", &["\u{61}", "\u{27}\u{2060}", "\u{30}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{30}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{30}"]),
+ ("\u{61}\u{27}\u{2060}\u{5f}", &["\u{61}", "\u{27}\u{2060}", "\u{5f}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{5f}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{5f}"]),
+ ("\u{61}\u{27}\u{2060}\u{1f1e6}", &["\u{61}", "\u{27}\u{2060}", "\u{1f1e6}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{1f1e6}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{1f1e6}"]),
+ ("\u{61}\u{27}\u{2060}\u{5d0}", &["\u{61}\u{27}\u{2060}\u{5d0}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{5d0}", &["\u{61}\u{27}\u{2060}\u{308}\u{5d0}"]),
+ ("\u{61}\u{27}\u{2060}\u{22}", &["\u{61}", "\u{27}\u{2060}", "\u{22}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{22}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{22}"]),
+ ("\u{61}\u{27}\u{2060}\u{27}", &["\u{61}", "\u{27}\u{2060}", "\u{27}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{27}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{27}"]),
+ ("\u{61}\u{27}\u{2060}\u{231a}", &["\u{61}", "\u{27}\u{2060}", "\u{231a}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{231a}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{231a}"]),
+ ("\u{61}\u{27}\u{2060}\u{20}", &["\u{61}", "\u{27}\u{2060}", "\u{20}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{20}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{20}"]),
+ ("\u{61}\u{27}\u{2060}\u{ad}", &["\u{61}", "\u{27}\u{2060}\u{ad}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{ad}", &["\u{61}", "\u{27}\u{2060}\u{308}\u{ad}"]),
+ ("\u{61}\u{27}\u{2060}\u{300}", &["\u{61}", "\u{27}\u{2060}\u{300}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{300}", &["\u{61}", "\u{27}\u{2060}\u{308}\u{300}"]),
+ ("\u{61}\u{27}\u{2060}\u{200d}", &["\u{61}", "\u{27}\u{2060}\u{200d}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{200d}", &["\u{61}", "\u{27}\u{2060}\u{308}\u{200d}"]),
+ ("\u{61}\u{27}\u{2060}\u{61}\u{2060}", &["\u{61}\u{27}\u{2060}\u{61}\u{2060}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{61}\u{2060}",
+ &["\u{61}\u{27}\u{2060}\u{308}\u{61}\u{2060}"]), ("\u{61}\u{27}\u{2060}\u{61}\u{3a}",
+ &["\u{61}\u{27}\u{2060}\u{61}", "\u{3a}"]), ("\u{61}\u{27}\u{2060}\u{308}\u{61}\u{3a}",
+ &["\u{61}\u{27}\u{2060}\u{308}\u{61}", "\u{3a}"]), ("\u{61}\u{27}\u{2060}\u{61}\u{27}",
+ &["\u{61}\u{27}\u{2060}\u{61}", "\u{27}"]), ("\u{61}\u{27}\u{2060}\u{308}\u{61}\u{27}",
+ &["\u{61}\u{27}\u{2060}\u{308}\u{61}", "\u{27}"]),
+ ("\u{61}\u{27}\u{2060}\u{61}\u{27}\u{2060}", &["\u{61}\u{27}\u{2060}\u{61}",
+ "\u{27}\u{2060}"]), ("\u{61}\u{27}\u{2060}\u{308}\u{61}\u{27}\u{2060}",
+ &["\u{61}\u{27}\u{2060}\u{308}\u{61}", "\u{27}\u{2060}"]),
+ ("\u{61}\u{27}\u{2060}\u{61}\u{2c}", &["\u{61}\u{27}\u{2060}\u{61}", "\u{2c}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{61}\u{2c}", &["\u{61}\u{27}\u{2060}\u{308}\u{61}",
+ "\u{2c}"]), ("\u{61}\u{27}\u{2060}\u{31}\u{3a}", &["\u{61}", "\u{27}\u{2060}", "\u{31}",
+ "\u{3a}"]), ("\u{61}\u{27}\u{2060}\u{308}\u{31}\u{3a}", &["\u{61}", "\u{27}\u{2060}\u{308}",
+ "\u{31}", "\u{3a}"]), ("\u{61}\u{27}\u{2060}\u{31}\u{27}", &["\u{61}", "\u{27}\u{2060}",
+ "\u{31}", "\u{27}"]), ("\u{61}\u{27}\u{2060}\u{308}\u{31}\u{27}", &["\u{61}",
+ "\u{27}\u{2060}\u{308}", "\u{31}", "\u{27}"]), ("\u{61}\u{27}\u{2060}\u{31}\u{2c}",
+ &["\u{61}", "\u{27}\u{2060}", "\u{31}", "\u{2c}"]),
+ ("\u{61}\u{27}\u{2060}\u{308}\u{31}\u{2c}", &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{31}",
+ "\u{2c}"]), ("\u{61}\u{27}\u{2060}\u{31}\u{2e}\u{2060}", &["\u{61}", "\u{27}\u{2060}",
+ "\u{31}", "\u{2e}\u{2060}"]), ("\u{61}\u{27}\u{2060}\u{308}\u{31}\u{2e}\u{2060}",
+ &["\u{61}", "\u{27}\u{2060}\u{308}", "\u{31}", "\u{2e}\u{2060}"]), ("\u{61}\u{2c}\u{1}",
+ &["\u{61}", "\u{2c}", "\u{1}"]), ("\u{61}\u{2c}\u{308}\u{1}", &["\u{61}", "\u{2c}\u{308}",
+ "\u{1}"]), ("\u{61}\u{2c}\u{d}", &["\u{61}", "\u{2c}", "\u{d}"]),
+ ("\u{61}\u{2c}\u{308}\u{d}", &["\u{61}", "\u{2c}\u{308}", "\u{d}"]), ("\u{61}\u{2c}\u{a}",
+ &["\u{61}", "\u{2c}", "\u{a}"]), ("\u{61}\u{2c}\u{308}\u{a}", &["\u{61}", "\u{2c}\u{308}",
+ "\u{a}"]), ("\u{61}\u{2c}\u{b}", &["\u{61}", "\u{2c}", "\u{b}"]),
+ ("\u{61}\u{2c}\u{308}\u{b}", &["\u{61}", "\u{2c}\u{308}", "\u{b}"]),
+ ("\u{61}\u{2c}\u{3031}", &["\u{61}", "\u{2c}", "\u{3031}"]), ("\u{61}\u{2c}\u{308}\u{3031}",
+ &["\u{61}", "\u{2c}\u{308}", "\u{3031}"]), ("\u{61}\u{2c}\u{41}", &["\u{61}", "\u{2c}",
+ "\u{41}"]), ("\u{61}\u{2c}\u{308}\u{41}", &["\u{61}", "\u{2c}\u{308}", "\u{41}"]),
+ ("\u{61}\u{2c}\u{3a}", &["\u{61}", "\u{2c}", "\u{3a}"]), ("\u{61}\u{2c}\u{308}\u{3a}",
+ &["\u{61}", "\u{2c}\u{308}", "\u{3a}"]), ("\u{61}\u{2c}\u{2c}", &["\u{61}", "\u{2c}",
+ "\u{2c}"]), ("\u{61}\u{2c}\u{308}\u{2c}", &["\u{61}", "\u{2c}\u{308}", "\u{2c}"]),
+ ("\u{61}\u{2c}\u{2e}", &["\u{61}", "\u{2c}", "\u{2e}"]), ("\u{61}\u{2c}\u{308}\u{2e}",
+ &["\u{61}", "\u{2c}\u{308}", "\u{2e}"]), ("\u{61}\u{2c}\u{30}", &["\u{61}", "\u{2c}",
+ "\u{30}"]), ("\u{61}\u{2c}\u{308}\u{30}", &["\u{61}", "\u{2c}\u{308}", "\u{30}"]),
+ ("\u{61}\u{2c}\u{5f}", &["\u{61}", "\u{2c}", "\u{5f}"]), ("\u{61}\u{2c}\u{308}\u{5f}",
+ &["\u{61}", "\u{2c}\u{308}", "\u{5f}"]), ("\u{61}\u{2c}\u{1f1e6}", &["\u{61}", "\u{2c}",
+ "\u{1f1e6}"]), ("\u{61}\u{2c}\u{308}\u{1f1e6}", &["\u{61}", "\u{2c}\u{308}", "\u{1f1e6}"]),
+ ("\u{61}\u{2c}\u{5d0}", &["\u{61}", "\u{2c}", "\u{5d0}"]), ("\u{61}\u{2c}\u{308}\u{5d0}",
+ &["\u{61}", "\u{2c}\u{308}", "\u{5d0}"]), ("\u{61}\u{2c}\u{22}", &["\u{61}", "\u{2c}",
+ "\u{22}"]), ("\u{61}\u{2c}\u{308}\u{22}", &["\u{61}", "\u{2c}\u{308}", "\u{22}"]),
+ ("\u{61}\u{2c}\u{27}", &["\u{61}", "\u{2c}", "\u{27}"]), ("\u{61}\u{2c}\u{308}\u{27}",
+ &["\u{61}", "\u{2c}\u{308}", "\u{27}"]), ("\u{61}\u{2c}\u{231a}", &["\u{61}", "\u{2c}",
+ "\u{231a}"]), ("\u{61}\u{2c}\u{308}\u{231a}", &["\u{61}", "\u{2c}\u{308}", "\u{231a}"]),
+ ("\u{61}\u{2c}\u{20}", &["\u{61}", "\u{2c}", "\u{20}"]), ("\u{61}\u{2c}\u{308}\u{20}",
+ &["\u{61}", "\u{2c}\u{308}", "\u{20}"]), ("\u{61}\u{2c}\u{ad}", &["\u{61}",
+ "\u{2c}\u{ad}"]), ("\u{61}\u{2c}\u{308}\u{ad}", &["\u{61}", "\u{2c}\u{308}\u{ad}"]),
+ ("\u{61}\u{2c}\u{300}", &["\u{61}", "\u{2c}\u{300}"]), ("\u{61}\u{2c}\u{308}\u{300}",
+ &["\u{61}", "\u{2c}\u{308}\u{300}"]), ("\u{61}\u{2c}\u{200d}", &["\u{61}",
+ "\u{2c}\u{200d}"]), ("\u{61}\u{2c}\u{308}\u{200d}", &["\u{61}", "\u{2c}\u{308}\u{200d}"]),
+ ("\u{61}\u{2c}\u{61}\u{2060}", &["\u{61}", "\u{2c}", "\u{61}\u{2060}"]),
+ ("\u{61}\u{2c}\u{308}\u{61}\u{2060}", &["\u{61}", "\u{2c}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{61}\u{2c}\u{61}\u{3a}", &["\u{61}", "\u{2c}", "\u{61}", "\u{3a}"]),
+ ("\u{61}\u{2c}\u{308}\u{61}\u{3a}", &["\u{61}", "\u{2c}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{61}\u{2c}\u{61}\u{27}", &["\u{61}", "\u{2c}", "\u{61}", "\u{27}"]),
+ ("\u{61}\u{2c}\u{308}\u{61}\u{27}", &["\u{61}", "\u{2c}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{61}\u{2c}\u{61}\u{27}\u{2060}", &["\u{61}", "\u{2c}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{61}\u{2c}\u{308}\u{61}\u{27}\u{2060}", &["\u{61}", "\u{2c}\u{308}", "\u{61}",
+ "\u{27}\u{2060}"]), ("\u{61}\u{2c}\u{61}\u{2c}", &["\u{61}", "\u{2c}", "\u{61}", "\u{2c}"]),
+ ("\u{61}\u{2c}\u{308}\u{61}\u{2c}", &["\u{61}", "\u{2c}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{61}\u{2c}\u{31}\u{3a}", &["\u{61}", "\u{2c}", "\u{31}", "\u{3a}"]),
+ ("\u{61}\u{2c}\u{308}\u{31}\u{3a}", &["\u{61}", "\u{2c}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{61}\u{2c}\u{31}\u{27}", &["\u{61}", "\u{2c}", "\u{31}", "\u{27}"]),
+ ("\u{61}\u{2c}\u{308}\u{31}\u{27}", &["\u{61}", "\u{2c}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{61}\u{2c}\u{31}\u{2c}", &["\u{61}", "\u{2c}", "\u{31}", "\u{2c}"]),
+ ("\u{61}\u{2c}\u{308}\u{31}\u{2c}", &["\u{61}", "\u{2c}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{61}\u{2c}\u{31}\u{2e}\u{2060}", &["\u{61}", "\u{2c}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{61}\u{2c}\u{308}\u{31}\u{2e}\u{2060}", &["\u{61}", "\u{2c}\u{308}", "\u{31}",
+ "\u{2e}\u{2060}"]), ("\u{31}\u{3a}\u{1}", &["\u{31}", "\u{3a}", "\u{1}"]),
+ ("\u{31}\u{3a}\u{308}\u{1}", &["\u{31}", "\u{3a}\u{308}", "\u{1}"]), ("\u{31}\u{3a}\u{d}",
+ &["\u{31}", "\u{3a}", "\u{d}"]), ("\u{31}\u{3a}\u{308}\u{d}", &["\u{31}", "\u{3a}\u{308}",
+ "\u{d}"]), ("\u{31}\u{3a}\u{a}", &["\u{31}", "\u{3a}", "\u{a}"]),
+ ("\u{31}\u{3a}\u{308}\u{a}", &["\u{31}", "\u{3a}\u{308}", "\u{a}"]), ("\u{31}\u{3a}\u{b}",
+ &["\u{31}", "\u{3a}", "\u{b}"]), ("\u{31}\u{3a}\u{308}\u{b}", &["\u{31}", "\u{3a}\u{308}",
+ "\u{b}"]), ("\u{31}\u{3a}\u{3031}", &["\u{31}", "\u{3a}", "\u{3031}"]),
+ ("\u{31}\u{3a}\u{308}\u{3031}", &["\u{31}", "\u{3a}\u{308}", "\u{3031}"]),
+ ("\u{31}\u{3a}\u{41}", &["\u{31}", "\u{3a}", "\u{41}"]), ("\u{31}\u{3a}\u{308}\u{41}",
+ &["\u{31}", "\u{3a}\u{308}", "\u{41}"]), ("\u{31}\u{3a}\u{3a}", &["\u{31}", "\u{3a}",
+ "\u{3a}"]), ("\u{31}\u{3a}\u{308}\u{3a}", &["\u{31}", "\u{3a}\u{308}", "\u{3a}"]),
+ ("\u{31}\u{3a}\u{2c}", &["\u{31}", "\u{3a}", "\u{2c}"]), ("\u{31}\u{3a}\u{308}\u{2c}",
+ &["\u{31}", "\u{3a}\u{308}", "\u{2c}"]), ("\u{31}\u{3a}\u{2e}", &["\u{31}", "\u{3a}",
+ "\u{2e}"]), ("\u{31}\u{3a}\u{308}\u{2e}", &["\u{31}", "\u{3a}\u{308}", "\u{2e}"]),
+ ("\u{31}\u{3a}\u{30}", &["\u{31}", "\u{3a}", "\u{30}"]), ("\u{31}\u{3a}\u{308}\u{30}",
+ &["\u{31}", "\u{3a}\u{308}", "\u{30}"]), ("\u{31}\u{3a}\u{5f}", &["\u{31}", "\u{3a}",
+ "\u{5f}"]), ("\u{31}\u{3a}\u{308}\u{5f}", &["\u{31}", "\u{3a}\u{308}", "\u{5f}"]),
+ ("\u{31}\u{3a}\u{1f1e6}", &["\u{31}", "\u{3a}", "\u{1f1e6}"]),
+ ("\u{31}\u{3a}\u{308}\u{1f1e6}", &["\u{31}", "\u{3a}\u{308}", "\u{1f1e6}"]),
+ ("\u{31}\u{3a}\u{5d0}", &["\u{31}", "\u{3a}", "\u{5d0}"]), ("\u{31}\u{3a}\u{308}\u{5d0}",
+ &["\u{31}", "\u{3a}\u{308}", "\u{5d0}"]), ("\u{31}\u{3a}\u{22}", &["\u{31}", "\u{3a}",
+ "\u{22}"]), ("\u{31}\u{3a}\u{308}\u{22}", &["\u{31}", "\u{3a}\u{308}", "\u{22}"]),
+ ("\u{31}\u{3a}\u{27}", &["\u{31}", "\u{3a}", "\u{27}"]), ("\u{31}\u{3a}\u{308}\u{27}",
+ &["\u{31}", "\u{3a}\u{308}", "\u{27}"]), ("\u{31}\u{3a}\u{231a}", &["\u{31}", "\u{3a}",
+ "\u{231a}"]), ("\u{31}\u{3a}\u{308}\u{231a}", &["\u{31}", "\u{3a}\u{308}", "\u{231a}"]),
+ ("\u{31}\u{3a}\u{20}", &["\u{31}", "\u{3a}", "\u{20}"]), ("\u{31}\u{3a}\u{308}\u{20}",
+ &["\u{31}", "\u{3a}\u{308}", "\u{20}"]), ("\u{31}\u{3a}\u{ad}", &["\u{31}",
+ "\u{3a}\u{ad}"]), ("\u{31}\u{3a}\u{308}\u{ad}", &["\u{31}", "\u{3a}\u{308}\u{ad}"]),
+ ("\u{31}\u{3a}\u{300}", &["\u{31}", "\u{3a}\u{300}"]), ("\u{31}\u{3a}\u{308}\u{300}",
+ &["\u{31}", "\u{3a}\u{308}\u{300}"]), ("\u{31}\u{3a}\u{200d}", &["\u{31}",
+ "\u{3a}\u{200d}"]), ("\u{31}\u{3a}\u{308}\u{200d}", &["\u{31}", "\u{3a}\u{308}\u{200d}"]),
+ ("\u{31}\u{3a}\u{61}\u{2060}", &["\u{31}", "\u{3a}", "\u{61}\u{2060}"]),
+ ("\u{31}\u{3a}\u{308}\u{61}\u{2060}", &["\u{31}", "\u{3a}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{31}\u{3a}\u{61}\u{3a}", &["\u{31}", "\u{3a}", "\u{61}", "\u{3a}"]),
+ ("\u{31}\u{3a}\u{308}\u{61}\u{3a}", &["\u{31}", "\u{3a}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{31}\u{3a}\u{61}\u{27}", &["\u{31}", "\u{3a}", "\u{61}", "\u{27}"]),
+ ("\u{31}\u{3a}\u{308}\u{61}\u{27}", &["\u{31}", "\u{3a}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{31}\u{3a}\u{61}\u{27}\u{2060}", &["\u{31}", "\u{3a}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{31}\u{3a}\u{308}\u{61}\u{27}\u{2060}", &["\u{31}", "\u{3a}\u{308}", "\u{61}",
+ "\u{27}\u{2060}"]), ("\u{31}\u{3a}\u{61}\u{2c}", &["\u{31}", "\u{3a}", "\u{61}", "\u{2c}"]),
+ ("\u{31}\u{3a}\u{308}\u{61}\u{2c}", &["\u{31}", "\u{3a}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{31}\u{3a}\u{31}\u{3a}", &["\u{31}", "\u{3a}", "\u{31}", "\u{3a}"]),
+ ("\u{31}\u{3a}\u{308}\u{31}\u{3a}", &["\u{31}", "\u{3a}\u{308}", "\u{31}", "\u{3a}"]),
+ ("\u{31}\u{3a}\u{31}\u{27}", &["\u{31}", "\u{3a}", "\u{31}", "\u{27}"]),
+ ("\u{31}\u{3a}\u{308}\u{31}\u{27}", &["\u{31}", "\u{3a}\u{308}", "\u{31}", "\u{27}"]),
+ ("\u{31}\u{3a}\u{31}\u{2c}", &["\u{31}", "\u{3a}", "\u{31}", "\u{2c}"]),
+ ("\u{31}\u{3a}\u{308}\u{31}\u{2c}", &["\u{31}", "\u{3a}\u{308}", "\u{31}", "\u{2c}"]),
+ ("\u{31}\u{3a}\u{31}\u{2e}\u{2060}", &["\u{31}", "\u{3a}", "\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{31}\u{3a}\u{308}\u{31}\u{2e}\u{2060}", &["\u{31}", "\u{3a}\u{308}", "\u{31}",
+ "\u{2e}\u{2060}"]), ("\u{31}\u{27}\u{1}", &["\u{31}", "\u{27}", "\u{1}"]),
+ ("\u{31}\u{27}\u{308}\u{1}", &["\u{31}", "\u{27}\u{308}", "\u{1}"]), ("\u{31}\u{27}\u{d}",
+ &["\u{31}", "\u{27}", "\u{d}"]), ("\u{31}\u{27}\u{308}\u{d}", &["\u{31}", "\u{27}\u{308}",
+ "\u{d}"]), ("\u{31}\u{27}\u{a}", &["\u{31}", "\u{27}", "\u{a}"]),
+ ("\u{31}\u{27}\u{308}\u{a}", &["\u{31}", "\u{27}\u{308}", "\u{a}"]), ("\u{31}\u{27}\u{b}",
+ &["\u{31}", "\u{27}", "\u{b}"]), ("\u{31}\u{27}\u{308}\u{b}", &["\u{31}", "\u{27}\u{308}",
+ "\u{b}"]), ("\u{31}\u{27}\u{3031}", &["\u{31}", "\u{27}", "\u{3031}"]),
+ ("\u{31}\u{27}\u{308}\u{3031}", &["\u{31}", "\u{27}\u{308}", "\u{3031}"]),
+ ("\u{31}\u{27}\u{41}", &["\u{31}", "\u{27}", "\u{41}"]), ("\u{31}\u{27}\u{308}\u{41}",
+ &["\u{31}", "\u{27}\u{308}", "\u{41}"]), ("\u{31}\u{27}\u{3a}", &["\u{31}", "\u{27}",
+ "\u{3a}"]), ("\u{31}\u{27}\u{308}\u{3a}", &["\u{31}", "\u{27}\u{308}", "\u{3a}"]),
+ ("\u{31}\u{27}\u{2c}", &["\u{31}", "\u{27}", "\u{2c}"]), ("\u{31}\u{27}\u{308}\u{2c}",
+ &["\u{31}", "\u{27}\u{308}", "\u{2c}"]), ("\u{31}\u{27}\u{2e}", &["\u{31}", "\u{27}",
+ "\u{2e}"]), ("\u{31}\u{27}\u{308}\u{2e}", &["\u{31}", "\u{27}\u{308}", "\u{2e}"]),
+ ("\u{31}\u{27}\u{30}", &["\u{31}\u{27}\u{30}"]), ("\u{31}\u{27}\u{308}\u{30}",
+ &["\u{31}\u{27}\u{308}\u{30}"]), ("\u{31}\u{27}\u{5f}", &["\u{31}", "\u{27}", "\u{5f}"]),
+ ("\u{31}\u{27}\u{308}\u{5f}", &["\u{31}", "\u{27}\u{308}", "\u{5f}"]),
+ ("\u{31}\u{27}\u{1f1e6}", &["\u{31}", "\u{27}", "\u{1f1e6}"]),
+ ("\u{31}\u{27}\u{308}\u{1f1e6}", &["\u{31}", "\u{27}\u{308}", "\u{1f1e6}"]),
+ ("\u{31}\u{27}\u{5d0}", &["\u{31}", "\u{27}", "\u{5d0}"]), ("\u{31}\u{27}\u{308}\u{5d0}",
+ &["\u{31}", "\u{27}\u{308}", "\u{5d0}"]), ("\u{31}\u{27}\u{22}", &["\u{31}", "\u{27}",
+ "\u{22}"]), ("\u{31}\u{27}\u{308}\u{22}", &["\u{31}", "\u{27}\u{308}", "\u{22}"]),
+ ("\u{31}\u{27}\u{27}", &["\u{31}", "\u{27}", "\u{27}"]), ("\u{31}\u{27}\u{308}\u{27}",
+ &["\u{31}", "\u{27}\u{308}", "\u{27}"]), ("\u{31}\u{27}\u{231a}", &["\u{31}", "\u{27}",
+ "\u{231a}"]), ("\u{31}\u{27}\u{308}\u{231a}", &["\u{31}", "\u{27}\u{308}", "\u{231a}"]),
+ ("\u{31}\u{27}\u{20}", &["\u{31}", "\u{27}", "\u{20}"]), ("\u{31}\u{27}\u{308}\u{20}",
+ &["\u{31}", "\u{27}\u{308}", "\u{20}"]), ("\u{31}\u{27}\u{ad}", &["\u{31}",
+ "\u{27}\u{ad}"]), ("\u{31}\u{27}\u{308}\u{ad}", &["\u{31}", "\u{27}\u{308}\u{ad}"]),
+ ("\u{31}\u{27}\u{300}", &["\u{31}", "\u{27}\u{300}"]), ("\u{31}\u{27}\u{308}\u{300}",
+ &["\u{31}", "\u{27}\u{308}\u{300}"]), ("\u{31}\u{27}\u{200d}", &["\u{31}",
+ "\u{27}\u{200d}"]), ("\u{31}\u{27}\u{308}\u{200d}", &["\u{31}", "\u{27}\u{308}\u{200d}"]),
+ ("\u{31}\u{27}\u{61}\u{2060}", &["\u{31}", "\u{27}", "\u{61}\u{2060}"]),
+ ("\u{31}\u{27}\u{308}\u{61}\u{2060}", &["\u{31}", "\u{27}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{31}\u{27}\u{61}\u{3a}", &["\u{31}", "\u{27}", "\u{61}", "\u{3a}"]),
+ ("\u{31}\u{27}\u{308}\u{61}\u{3a}", &["\u{31}", "\u{27}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{31}\u{27}\u{61}\u{27}", &["\u{31}", "\u{27}", "\u{61}", "\u{27}"]),
+ ("\u{31}\u{27}\u{308}\u{61}\u{27}", &["\u{31}", "\u{27}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{31}\u{27}\u{61}\u{27}\u{2060}", &["\u{31}", "\u{27}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{31}\u{27}\u{308}\u{61}\u{27}\u{2060}", &["\u{31}", "\u{27}\u{308}", "\u{61}",
+ "\u{27}\u{2060}"]), ("\u{31}\u{27}\u{61}\u{2c}", &["\u{31}", "\u{27}", "\u{61}", "\u{2c}"]),
+ ("\u{31}\u{27}\u{308}\u{61}\u{2c}", &["\u{31}", "\u{27}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{31}\u{27}\u{31}\u{3a}", &["\u{31}\u{27}\u{31}", "\u{3a}"]),
+ ("\u{31}\u{27}\u{308}\u{31}\u{3a}", &["\u{31}\u{27}\u{308}\u{31}", "\u{3a}"]),
+ ("\u{31}\u{27}\u{31}\u{27}", &["\u{31}\u{27}\u{31}", "\u{27}"]),
+ ("\u{31}\u{27}\u{308}\u{31}\u{27}", &["\u{31}\u{27}\u{308}\u{31}", "\u{27}"]),
+ ("\u{31}\u{27}\u{31}\u{2c}", &["\u{31}\u{27}\u{31}", "\u{2c}"]),
+ ("\u{31}\u{27}\u{308}\u{31}\u{2c}", &["\u{31}\u{27}\u{308}\u{31}", "\u{2c}"]),
+ ("\u{31}\u{27}\u{31}\u{2e}\u{2060}", &["\u{31}\u{27}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{31}\u{27}\u{308}\u{31}\u{2e}\u{2060}", &["\u{31}\u{27}\u{308}\u{31}",
+ "\u{2e}\u{2060}"]), ("\u{31}\u{2c}\u{1}", &["\u{31}", "\u{2c}", "\u{1}"]),
+ ("\u{31}\u{2c}\u{308}\u{1}", &["\u{31}", "\u{2c}\u{308}", "\u{1}"]), ("\u{31}\u{2c}\u{d}",
+ &["\u{31}", "\u{2c}", "\u{d}"]), ("\u{31}\u{2c}\u{308}\u{d}", &["\u{31}", "\u{2c}\u{308}",
+ "\u{d}"]), ("\u{31}\u{2c}\u{a}", &["\u{31}", "\u{2c}", "\u{a}"]),
+ ("\u{31}\u{2c}\u{308}\u{a}", &["\u{31}", "\u{2c}\u{308}", "\u{a}"]), ("\u{31}\u{2c}\u{b}",
+ &["\u{31}", "\u{2c}", "\u{b}"]), ("\u{31}\u{2c}\u{308}\u{b}", &["\u{31}", "\u{2c}\u{308}",
+ "\u{b}"]), ("\u{31}\u{2c}\u{3031}", &["\u{31}", "\u{2c}", "\u{3031}"]),
+ ("\u{31}\u{2c}\u{308}\u{3031}", &["\u{31}", "\u{2c}\u{308}", "\u{3031}"]),
+ ("\u{31}\u{2c}\u{41}", &["\u{31}", "\u{2c}", "\u{41}"]), ("\u{31}\u{2c}\u{308}\u{41}",
+ &["\u{31}", "\u{2c}\u{308}", "\u{41}"]), ("\u{31}\u{2c}\u{3a}", &["\u{31}", "\u{2c}",
+ "\u{3a}"]), ("\u{31}\u{2c}\u{308}\u{3a}", &["\u{31}", "\u{2c}\u{308}", "\u{3a}"]),
+ ("\u{31}\u{2c}\u{2c}", &["\u{31}", "\u{2c}", "\u{2c}"]), ("\u{31}\u{2c}\u{308}\u{2c}",
+ &["\u{31}", "\u{2c}\u{308}", "\u{2c}"]), ("\u{31}\u{2c}\u{2e}", &["\u{31}", "\u{2c}",
+ "\u{2e}"]), ("\u{31}\u{2c}\u{308}\u{2e}", &["\u{31}", "\u{2c}\u{308}", "\u{2e}"]),
+ ("\u{31}\u{2c}\u{30}", &["\u{31}\u{2c}\u{30}"]), ("\u{31}\u{2c}\u{308}\u{30}",
+ &["\u{31}\u{2c}\u{308}\u{30}"]), ("\u{31}\u{2c}\u{5f}", &["\u{31}", "\u{2c}", "\u{5f}"]),
+ ("\u{31}\u{2c}\u{308}\u{5f}", &["\u{31}", "\u{2c}\u{308}", "\u{5f}"]),
+ ("\u{31}\u{2c}\u{1f1e6}", &["\u{31}", "\u{2c}", "\u{1f1e6}"]),
+ ("\u{31}\u{2c}\u{308}\u{1f1e6}", &["\u{31}", "\u{2c}\u{308}", "\u{1f1e6}"]),
+ ("\u{31}\u{2c}\u{5d0}", &["\u{31}", "\u{2c}", "\u{5d0}"]), ("\u{31}\u{2c}\u{308}\u{5d0}",
+ &["\u{31}", "\u{2c}\u{308}", "\u{5d0}"]), ("\u{31}\u{2c}\u{22}", &["\u{31}", "\u{2c}",
+ "\u{22}"]), ("\u{31}\u{2c}\u{308}\u{22}", &["\u{31}", "\u{2c}\u{308}", "\u{22}"]),
+ ("\u{31}\u{2c}\u{27}", &["\u{31}", "\u{2c}", "\u{27}"]), ("\u{31}\u{2c}\u{308}\u{27}",
+ &["\u{31}", "\u{2c}\u{308}", "\u{27}"]), ("\u{31}\u{2c}\u{231a}", &["\u{31}", "\u{2c}",
+ "\u{231a}"]), ("\u{31}\u{2c}\u{308}\u{231a}", &["\u{31}", "\u{2c}\u{308}", "\u{231a}"]),
+ ("\u{31}\u{2c}\u{20}", &["\u{31}", "\u{2c}", "\u{20}"]), ("\u{31}\u{2c}\u{308}\u{20}",
+ &["\u{31}", "\u{2c}\u{308}", "\u{20}"]), ("\u{31}\u{2c}\u{ad}", &["\u{31}",
+ "\u{2c}\u{ad}"]), ("\u{31}\u{2c}\u{308}\u{ad}", &["\u{31}", "\u{2c}\u{308}\u{ad}"]),
+ ("\u{31}\u{2c}\u{300}", &["\u{31}", "\u{2c}\u{300}"]), ("\u{31}\u{2c}\u{308}\u{300}",
+ &["\u{31}", "\u{2c}\u{308}\u{300}"]), ("\u{31}\u{2c}\u{200d}", &["\u{31}",
+ "\u{2c}\u{200d}"]), ("\u{31}\u{2c}\u{308}\u{200d}", &["\u{31}", "\u{2c}\u{308}\u{200d}"]),
+ ("\u{31}\u{2c}\u{61}\u{2060}", &["\u{31}", "\u{2c}", "\u{61}\u{2060}"]),
+ ("\u{31}\u{2c}\u{308}\u{61}\u{2060}", &["\u{31}", "\u{2c}\u{308}", "\u{61}\u{2060}"]),
+ ("\u{31}\u{2c}\u{61}\u{3a}", &["\u{31}", "\u{2c}", "\u{61}", "\u{3a}"]),
+ ("\u{31}\u{2c}\u{308}\u{61}\u{3a}", &["\u{31}", "\u{2c}\u{308}", "\u{61}", "\u{3a}"]),
+ ("\u{31}\u{2c}\u{61}\u{27}", &["\u{31}", "\u{2c}", "\u{61}", "\u{27}"]),
+ ("\u{31}\u{2c}\u{308}\u{61}\u{27}", &["\u{31}", "\u{2c}\u{308}", "\u{61}", "\u{27}"]),
+ ("\u{31}\u{2c}\u{61}\u{27}\u{2060}", &["\u{31}", "\u{2c}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{31}\u{2c}\u{308}\u{61}\u{27}\u{2060}", &["\u{31}", "\u{2c}\u{308}", "\u{61}",
+ "\u{27}\u{2060}"]), ("\u{31}\u{2c}\u{61}\u{2c}", &["\u{31}", "\u{2c}", "\u{61}", "\u{2c}"]),
+ ("\u{31}\u{2c}\u{308}\u{61}\u{2c}", &["\u{31}", "\u{2c}\u{308}", "\u{61}", "\u{2c}"]),
+ ("\u{31}\u{2c}\u{31}\u{3a}", &["\u{31}\u{2c}\u{31}", "\u{3a}"]),
+ ("\u{31}\u{2c}\u{308}\u{31}\u{3a}", &["\u{31}\u{2c}\u{308}\u{31}", "\u{3a}"]),
+ ("\u{31}\u{2c}\u{31}\u{27}", &["\u{31}\u{2c}\u{31}", "\u{27}"]),
+ ("\u{31}\u{2c}\u{308}\u{31}\u{27}", &["\u{31}\u{2c}\u{308}\u{31}", "\u{27}"]),
+ ("\u{31}\u{2c}\u{31}\u{2c}", &["\u{31}\u{2c}\u{31}", "\u{2c}"]),
+ ("\u{31}\u{2c}\u{308}\u{31}\u{2c}", &["\u{31}\u{2c}\u{308}\u{31}", "\u{2c}"]),
+ ("\u{31}\u{2c}\u{31}\u{2e}\u{2060}", &["\u{31}\u{2c}\u{31}", "\u{2e}\u{2060}"]),
+ ("\u{31}\u{2c}\u{308}\u{31}\u{2e}\u{2060}", &["\u{31}\u{2c}\u{308}\u{31}",
+ "\u{2e}\u{2060}"]), ("\u{31}\u{2e}\u{2060}\u{1}", &["\u{31}", "\u{2e}\u{2060}", "\u{1}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{1}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{1}"]),
+ ("\u{31}\u{2e}\u{2060}\u{d}", &["\u{31}", "\u{2e}\u{2060}", "\u{d}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{d}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{d}"]),
+ ("\u{31}\u{2e}\u{2060}\u{a}", &["\u{31}", "\u{2e}\u{2060}", "\u{a}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{a}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{a}"]),
+ ("\u{31}\u{2e}\u{2060}\u{b}", &["\u{31}", "\u{2e}\u{2060}", "\u{b}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{b}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{b}"]),
+ ("\u{31}\u{2e}\u{2060}\u{3031}", &["\u{31}", "\u{2e}\u{2060}", "\u{3031}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{3031}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{3031}"]),
+ ("\u{31}\u{2e}\u{2060}\u{41}", &["\u{31}", "\u{2e}\u{2060}", "\u{41}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{41}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{41}"]),
+ ("\u{31}\u{2e}\u{2060}\u{3a}", &["\u{31}", "\u{2e}\u{2060}", "\u{3a}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{3a}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{3a}"]),
+ ("\u{31}\u{2e}\u{2060}\u{2c}", &["\u{31}", "\u{2e}\u{2060}", "\u{2c}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{2c}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{2c}"]),
+ ("\u{31}\u{2e}\u{2060}\u{2e}", &["\u{31}", "\u{2e}\u{2060}", "\u{2e}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{2e}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{2e}"]),
+ ("\u{31}\u{2e}\u{2060}\u{30}", &["\u{31}\u{2e}\u{2060}\u{30}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{30}", &["\u{31}\u{2e}\u{2060}\u{308}\u{30}"]),
+ ("\u{31}\u{2e}\u{2060}\u{5f}", &["\u{31}", "\u{2e}\u{2060}", "\u{5f}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{5f}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{5f}"]),
+ ("\u{31}\u{2e}\u{2060}\u{1f1e6}", &["\u{31}", "\u{2e}\u{2060}", "\u{1f1e6}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{1f1e6}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{1f1e6}"]),
+ ("\u{31}\u{2e}\u{2060}\u{5d0}", &["\u{31}", "\u{2e}\u{2060}", "\u{5d0}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{5d0}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{5d0}"]),
+ ("\u{31}\u{2e}\u{2060}\u{22}", &["\u{31}", "\u{2e}\u{2060}", "\u{22}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{22}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{22}"]),
+ ("\u{31}\u{2e}\u{2060}\u{27}", &["\u{31}", "\u{2e}\u{2060}", "\u{27}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{27}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{27}"]),
+ ("\u{31}\u{2e}\u{2060}\u{231a}", &["\u{31}", "\u{2e}\u{2060}", "\u{231a}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{231a}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{231a}"]),
+ ("\u{31}\u{2e}\u{2060}\u{20}", &["\u{31}", "\u{2e}\u{2060}", "\u{20}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{20}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{20}"]),
+ ("\u{31}\u{2e}\u{2060}\u{ad}", &["\u{31}", "\u{2e}\u{2060}\u{ad}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{ad}", &["\u{31}", "\u{2e}\u{2060}\u{308}\u{ad}"]),
+ ("\u{31}\u{2e}\u{2060}\u{300}", &["\u{31}", "\u{2e}\u{2060}\u{300}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{300}", &["\u{31}", "\u{2e}\u{2060}\u{308}\u{300}"]),
+ ("\u{31}\u{2e}\u{2060}\u{200d}", &["\u{31}", "\u{2e}\u{2060}\u{200d}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{200d}", &["\u{31}", "\u{2e}\u{2060}\u{308}\u{200d}"]),
+ ("\u{31}\u{2e}\u{2060}\u{61}\u{2060}", &["\u{31}", "\u{2e}\u{2060}", "\u{61}\u{2060}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{61}\u{2060}", &["\u{31}", "\u{2e}\u{2060}\u{308}",
+ "\u{61}\u{2060}"]), ("\u{31}\u{2e}\u{2060}\u{61}\u{3a}", &["\u{31}", "\u{2e}\u{2060}",
+ "\u{61}", "\u{3a}"]), ("\u{31}\u{2e}\u{2060}\u{308}\u{61}\u{3a}", &["\u{31}",
+ "\u{2e}\u{2060}\u{308}", "\u{61}", "\u{3a}"]), ("\u{31}\u{2e}\u{2060}\u{61}\u{27}",
+ &["\u{31}", "\u{2e}\u{2060}", "\u{61}", "\u{27}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{61}\u{27}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{61}",
+ "\u{27}"]), ("\u{31}\u{2e}\u{2060}\u{61}\u{27}\u{2060}", &["\u{31}", "\u{2e}\u{2060}",
+ "\u{61}", "\u{27}\u{2060}"]), ("\u{31}\u{2e}\u{2060}\u{308}\u{61}\u{27}\u{2060}",
+ &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{61}", "\u{27}\u{2060}"]),
+ ("\u{31}\u{2e}\u{2060}\u{61}\u{2c}", &["\u{31}", "\u{2e}\u{2060}", "\u{61}", "\u{2c}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{61}\u{2c}", &["\u{31}", "\u{2e}\u{2060}\u{308}", "\u{61}",
+ "\u{2c}"]), ("\u{31}\u{2e}\u{2060}\u{31}\u{3a}", &["\u{31}\u{2e}\u{2060}\u{31}", "\u{3a}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{31}\u{3a}", &["\u{31}\u{2e}\u{2060}\u{308}\u{31}",
+ "\u{3a}"]), ("\u{31}\u{2e}\u{2060}\u{31}\u{27}", &["\u{31}\u{2e}\u{2060}\u{31}", "\u{27}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{31}\u{27}", &["\u{31}\u{2e}\u{2060}\u{308}\u{31}",
+ "\u{27}"]), ("\u{31}\u{2e}\u{2060}\u{31}\u{2c}", &["\u{31}\u{2e}\u{2060}\u{31}", "\u{2c}"]),
+ ("\u{31}\u{2e}\u{2060}\u{308}\u{31}\u{2c}", &["\u{31}\u{2e}\u{2060}\u{308}\u{31}",
+ "\u{2c}"]), ("\u{31}\u{2e}\u{2060}\u{31}\u{2e}\u{2060}", &["\u{31}\u{2e}\u{2060}\u{31}",
+ "\u{2e}\u{2060}"]), ("\u{31}\u{2e}\u{2060}\u{308}\u{31}\u{2e}\u{2060}",
+ &["\u{31}\u{2e}\u{2060}\u{308}\u{31}", "\u{2e}\u{2060}"]), ("\u{d}\u{a}\u{61}\u{a}\u{308}",
+ &["\u{d}\u{a}", "\u{61}", "\u{a}", "\u{308}"]), ("\u{61}\u{308}", &["\u{61}\u{308}"]),
+ ("\u{20}\u{200d}\u{646}", &["\u{20}\u{200d}", "\u{646}"]), ("\u{646}\u{200d}\u{20}",
+ &["\u{646}\u{200d}", "\u{20}"]), ("\u{41}\u{41}\u{41}", &["\u{41}\u{41}\u{41}"]),
+ ("\u{41}\u{3a}\u{41}", &["\u{41}\u{3a}\u{41}"]), ("\u{41}\u{3a}\u{3a}\u{41}", &["\u{41}",
+ "\u{3a}", "\u{3a}", "\u{41}"]), ("\u{5d0}\u{27}", &["\u{5d0}\u{27}"]),
+ ("\u{5d0}\u{22}\u{5d0}", &["\u{5d0}\u{22}\u{5d0}"]), ("\u{41}\u{30}\u{30}\u{41}",
+ &["\u{41}\u{30}\u{30}\u{41}"]), ("\u{30}\u{2c}\u{30}", &["\u{30}\u{2c}\u{30}"]),
+ ("\u{30}\u{2c}\u{2c}\u{30}", &["\u{30}", "\u{2c}", "\u{2c}", "\u{30}"]),
+ ("\u{3031}\u{3031}", &["\u{3031}\u{3031}"]), ("\u{41}\u{5f}\u{30}\u{5f}\u{3031}\u{5f}",
+ &["\u{41}\u{5f}\u{30}\u{5f}\u{3031}\u{5f}"]), ("\u{41}\u{5f}\u{5f}\u{41}",
+ &["\u{41}\u{5f}\u{5f}\u{41}"]), ("\u{1f1e6}\u{1f1e7}\u{1f1e8}\u{62}",
+ &["\u{1f1e6}\u{1f1e7}", "\u{1f1e8}", "\u{62}"]), ("\u{61}\u{1f1e6}\u{1f1e7}\u{1f1e8}\u{62}",
+ &["\u{61}", "\u{1f1e6}\u{1f1e7}", "\u{1f1e8}", "\u{62}"]),
+ ("\u{61}\u{1f1e6}\u{1f1e7}\u{200d}\u{1f1e8}\u{62}", &["\u{61}",
+ "\u{1f1e6}\u{1f1e7}\u{200d}", "\u{1f1e8}", "\u{62}"]),
+ ("\u{61}\u{1f1e6}\u{200d}\u{1f1e7}\u{1f1e8}\u{62}", &["\u{61}",
+ "\u{1f1e6}\u{200d}\u{1f1e7}", "\u{1f1e8}", "\u{62}"]),
+ ("\u{61}\u{1f1e6}\u{1f1e7}\u{1f1e8}\u{1f1e9}\u{62}", &["\u{61}", "\u{1f1e6}\u{1f1e7}",
+ "\u{1f1e8}\u{1f1e9}", "\u{62}"]), ("\u{1f476}\u{1f3ff}\u{1f476}", &["\u{1f476}\u{1f3ff}",
+ "\u{1f476}"]), ("\u{1f6d1}\u{200d}\u{1f6d1}", &["\u{1f6d1}\u{200d}\u{1f6d1}"]),
+ ("\u{61}\u{200d}\u{1f6d1}", &["\u{61}\u{200d}\u{1f6d1}"]), ("\u{2701}\u{200d}\u{2701}",
+ &["\u{2701}\u{200d}\u{2701}"]), ("\u{61}\u{200d}\u{2701}", &["\u{61}\u{200d}\u{2701}"]),
+ ("\u{1f476}\u{1f3ff}\u{308}\u{200d}\u{1f476}\u{1f3ff}",
+ &["\u{1f476}\u{1f3ff}\u{308}\u{200d}\u{1f476}\u{1f3ff}"]), ("\u{1f6d1}\u{1f3ff}",
+ &["\u{1f6d1}\u{1f3ff}"]), ("\u{200d}\u{1f6d1}\u{1f3ff}", &["\u{200d}\u{1f6d1}\u{1f3ff}"]),
+ ("\u{200d}\u{1f6d1}", &["\u{200d}\u{1f6d1}"]), ("\u{200d}\u{1f6d1}",
+ &["\u{200d}\u{1f6d1}"]), ("\u{1f6d1}\u{1f6d1}", &["\u{1f6d1}", "\u{1f6d1}"]),
+ ("\u{61}\u{308}\u{200d}\u{308}\u{62}", &["\u{61}\u{308}\u{200d}\u{308}\u{62}"]),
+ ("\u{61}\u{20}\u{20}\u{62}", &["\u{61}", "\u{20}\u{20}", "\u{62}"]),
+ ("\u{31}\u{3a}\u{3a}\u{31}", &["\u{31}", "\u{3a}", "\u{3a}", "\u{31}"]),
+ ("\u{31}\u{5f}\u{31}\u{3a}\u{3a}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{3a}", "\u{3a}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{3a}\u{3a}\u{31}", &["\u{31}\u{5f}\u{61}", "\u{3a}",
+ "\u{3a}", "\u{31}"]), ("\u{31}\u{3a}\u{3a}\u{61}", &["\u{31}", "\u{3a}", "\u{3a}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{3a}\u{3a}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{3a}",
+ "\u{3a}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{3a}\u{3a}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{3a}", "\u{3a}", "\u{61}"]), ("\u{31}\u{3a}\u{2e}\u{31}", &["\u{31}", "\u{3a}", "\u{2e}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{31}\u{3a}\u{2e}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{3a}",
+ "\u{2e}", "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{3a}\u{2e}\u{31}", &["\u{31}\u{5f}\u{61}",
+ "\u{3a}", "\u{2e}", "\u{31}"]), ("\u{31}\u{3a}\u{2e}\u{61}", &["\u{31}", "\u{3a}", "\u{2e}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{3a}\u{2e}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{3a}",
+ "\u{2e}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{3a}\u{2e}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{3a}", "\u{2e}", "\u{61}"]), ("\u{31}\u{3a}\u{2c}\u{31}", &["\u{31}", "\u{3a}", "\u{2c}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{31}\u{3a}\u{2c}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{3a}",
+ "\u{2c}", "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{3a}\u{2c}\u{31}", &["\u{31}\u{5f}\u{61}",
+ "\u{3a}", "\u{2c}", "\u{31}"]), ("\u{31}\u{3a}\u{2c}\u{61}", &["\u{31}", "\u{3a}", "\u{2c}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{3a}\u{2c}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{3a}",
+ "\u{2c}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{3a}\u{2c}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{3a}", "\u{2c}", "\u{61}"]), ("\u{31}\u{2e}\u{3a}\u{31}", &["\u{31}", "\u{2e}", "\u{3a}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{31}\u{2e}\u{3a}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{2e}",
+ "\u{3a}", "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{2e}\u{3a}\u{31}", &["\u{31}\u{5f}\u{61}",
+ "\u{2e}", "\u{3a}", "\u{31}"]), ("\u{31}\u{2e}\u{3a}\u{61}", &["\u{31}", "\u{2e}", "\u{3a}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{2e}\u{3a}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{2e}",
+ "\u{3a}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{2e}\u{3a}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{2e}", "\u{3a}", "\u{61}"]), ("\u{31}\u{2e}\u{2e}\u{31}", &["\u{31}", "\u{2e}", "\u{2e}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{31}\u{2e}\u{2e}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{2e}",
+ "\u{2e}", "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{2e}\u{2e}\u{31}", &["\u{31}\u{5f}\u{61}",
+ "\u{2e}", "\u{2e}", "\u{31}"]), ("\u{31}\u{2e}\u{2e}\u{61}", &["\u{31}", "\u{2e}", "\u{2e}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{2e}\u{2e}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{2e}",
+ "\u{2e}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{2e}\u{2e}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{2e}", "\u{2e}", "\u{61}"]), ("\u{31}\u{2e}\u{2c}\u{31}", &["\u{31}", "\u{2e}", "\u{2c}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{31}\u{2e}\u{2c}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{2e}",
+ "\u{2c}", "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{2e}\u{2c}\u{31}", &["\u{31}\u{5f}\u{61}",
+ "\u{2e}", "\u{2c}", "\u{31}"]), ("\u{31}\u{2e}\u{2c}\u{61}", &["\u{31}", "\u{2e}", "\u{2c}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{2e}\u{2c}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{2e}",
+ "\u{2c}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{2e}\u{2c}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{2e}", "\u{2c}", "\u{61}"]), ("\u{31}\u{2c}\u{3a}\u{31}", &["\u{31}", "\u{2c}", "\u{3a}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{31}\u{2c}\u{3a}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{2c}",
+ "\u{3a}", "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{2c}\u{3a}\u{31}", &["\u{31}\u{5f}\u{61}",
+ "\u{2c}", "\u{3a}", "\u{31}"]), ("\u{31}\u{2c}\u{3a}\u{61}", &["\u{31}", "\u{2c}", "\u{3a}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{2c}\u{3a}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{2c}",
+ "\u{3a}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{2c}\u{3a}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{2c}", "\u{3a}", "\u{61}"]), ("\u{31}\u{2c}\u{2e}\u{31}", &["\u{31}", "\u{2c}", "\u{2e}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{31}\u{2c}\u{2e}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{2c}",
+ "\u{2e}", "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{2c}\u{2e}\u{31}", &["\u{31}\u{5f}\u{61}",
+ "\u{2c}", "\u{2e}", "\u{31}"]), ("\u{31}\u{2c}\u{2e}\u{61}", &["\u{31}", "\u{2c}", "\u{2e}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{2c}\u{2e}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{2c}",
+ "\u{2e}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{2c}\u{2e}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{2c}", "\u{2e}", "\u{61}"]), ("\u{31}\u{2c}\u{2c}\u{31}", &["\u{31}", "\u{2c}", "\u{2c}",
+ "\u{31}"]), ("\u{31}\u{5f}\u{31}\u{2c}\u{2c}\u{31}", &["\u{31}\u{5f}\u{31}", "\u{2c}",
+ "\u{2c}", "\u{31}"]), ("\u{31}\u{5f}\u{61}\u{2c}\u{2c}\u{31}", &["\u{31}\u{5f}\u{61}",
+ "\u{2c}", "\u{2c}", "\u{31}"]), ("\u{31}\u{2c}\u{2c}\u{61}", &["\u{31}", "\u{2c}", "\u{2c}",
+ "\u{61}"]), ("\u{31}\u{5f}\u{31}\u{2c}\u{2c}\u{61}", &["\u{31}\u{5f}\u{31}", "\u{2c}",
+ "\u{2c}", "\u{61}"]), ("\u{31}\u{5f}\u{61}\u{2c}\u{2c}\u{61}", &["\u{31}\u{5f}\u{61}",
+ "\u{2c}", "\u{2c}", "\u{61}"]), ("\u{61}\u{3a}\u{3a}\u{31}", &["\u{61}", "\u{3a}", "\u{3a}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{3a}\u{3a}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{3a}",
+ "\u{3a}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{3a}\u{3a}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{3a}", "\u{3a}", "\u{31}"]), ("\u{61}\u{3a}\u{3a}\u{61}", &["\u{61}", "\u{3a}", "\u{3a}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{3a}\u{3a}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{3a}",
+ "\u{3a}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{3a}\u{3a}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{3a}", "\u{3a}", "\u{61}"]), ("\u{61}\u{3a}\u{2e}\u{31}", &["\u{61}", "\u{3a}", "\u{2e}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{3a}\u{2e}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{3a}",
+ "\u{2e}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{3a}\u{2e}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{3a}", "\u{2e}", "\u{31}"]), ("\u{61}\u{3a}\u{2e}\u{61}", &["\u{61}", "\u{3a}", "\u{2e}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{3a}\u{2e}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{3a}",
+ "\u{2e}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{3a}\u{2e}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{3a}", "\u{2e}", "\u{61}"]), ("\u{61}\u{3a}\u{2c}\u{31}", &["\u{61}", "\u{3a}", "\u{2c}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{3a}\u{2c}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{3a}",
+ "\u{2c}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{3a}\u{2c}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{3a}", "\u{2c}", "\u{31}"]), ("\u{61}\u{3a}\u{2c}\u{61}", &["\u{61}", "\u{3a}", "\u{2c}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{3a}\u{2c}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{3a}",
+ "\u{2c}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{3a}\u{2c}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{3a}", "\u{2c}", "\u{61}"]), ("\u{61}\u{2e}\u{3a}\u{31}", &["\u{61}", "\u{2e}", "\u{3a}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{2e}\u{3a}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{2e}",
+ "\u{3a}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{2e}\u{3a}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{2e}", "\u{3a}", "\u{31}"]), ("\u{61}\u{2e}\u{3a}\u{61}", &["\u{61}", "\u{2e}", "\u{3a}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{2e}\u{3a}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{2e}",
+ "\u{3a}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{2e}\u{3a}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{2e}", "\u{3a}", "\u{61}"]), ("\u{61}\u{2e}\u{2e}\u{31}", &["\u{61}", "\u{2e}", "\u{2e}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{2e}\u{2e}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{2e}",
+ "\u{2e}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{2e}\u{2e}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{2e}", "\u{2e}", "\u{31}"]), ("\u{61}\u{2e}\u{2e}\u{61}", &["\u{61}", "\u{2e}", "\u{2e}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{2e}\u{2e}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{2e}",
+ "\u{2e}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{2e}\u{2e}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{2e}", "\u{2e}", "\u{61}"]), ("\u{61}\u{2e}\u{2c}\u{31}", &["\u{61}", "\u{2e}", "\u{2c}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{2e}\u{2c}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{2e}",
+ "\u{2c}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{2e}\u{2c}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{2e}", "\u{2c}", "\u{31}"]), ("\u{61}\u{2e}\u{2c}\u{61}", &["\u{61}", "\u{2e}", "\u{2c}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{2e}\u{2c}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{2e}",
+ "\u{2c}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{2e}\u{2c}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{2e}", "\u{2c}", "\u{61}"]), ("\u{61}\u{2c}\u{3a}\u{31}", &["\u{61}", "\u{2c}", "\u{3a}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{2c}\u{3a}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{2c}",
+ "\u{3a}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{2c}\u{3a}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{2c}", "\u{3a}", "\u{31}"]), ("\u{61}\u{2c}\u{3a}\u{61}", &["\u{61}", "\u{2c}", "\u{3a}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{2c}\u{3a}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{2c}",
+ "\u{3a}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{2c}\u{3a}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{2c}", "\u{3a}", "\u{61}"]), ("\u{61}\u{2c}\u{2e}\u{31}", &["\u{61}", "\u{2c}", "\u{2e}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{2c}\u{2e}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{2c}",
+ "\u{2e}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{2c}\u{2e}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{2c}", "\u{2e}", "\u{31}"]), ("\u{61}\u{2c}\u{2e}\u{61}", &["\u{61}", "\u{2c}", "\u{2e}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{2c}\u{2e}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{2c}",
+ "\u{2e}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{2c}\u{2e}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{2c}", "\u{2e}", "\u{61}"]), ("\u{61}\u{2c}\u{2c}\u{31}", &["\u{61}", "\u{2c}", "\u{2c}",
+ "\u{31}"]), ("\u{61}\u{5f}\u{31}\u{2c}\u{2c}\u{31}", &["\u{61}\u{5f}\u{31}", "\u{2c}",
+ "\u{2c}", "\u{31}"]), ("\u{61}\u{5f}\u{61}\u{2c}\u{2c}\u{31}", &["\u{61}\u{5f}\u{61}",
+ "\u{2c}", "\u{2c}", "\u{31}"]), ("\u{61}\u{2c}\u{2c}\u{61}", &["\u{61}", "\u{2c}", "\u{2c}",
+ "\u{61}"]), ("\u{61}\u{5f}\u{31}\u{2c}\u{2c}\u{61}", &["\u{61}\u{5f}\u{31}", "\u{2c}",
+ "\u{2c}", "\u{61}"]), ("\u{61}\u{5f}\u{61}\u{2c}\u{2c}\u{61}", &["\u{61}\u{5f}\u{61}",
+ "\u{2c}", "\u{2c}", "\u{61}"])
+ ];
+
+ // official Unicode test data
+ // http://www.unicode.org/Public/12.0.0/ucd/auxiliary/SentenceBreakTest.txt
+ pub const TEST_SENTENCE: &'static [(&'static str, &'static [&'static str])] = &[
+ ("\u{1}\u{1}", &["\u{1}\u{1}"]), ("\u{1}\u{308}\u{1}", &["\u{1}\u{308}\u{1}"]),
+ ("\u{1}\u{d}", &["\u{1}\u{d}"]), ("\u{1}\u{308}\u{d}", &["\u{1}\u{308}\u{d}"]),
+ ("\u{1}\u{a}", &["\u{1}\u{a}"]), ("\u{1}\u{308}\u{a}", &["\u{1}\u{308}\u{a}"]),
+ ("\u{1}\u{85}", &["\u{1}\u{85}"]), ("\u{1}\u{308}\u{85}", &["\u{1}\u{308}\u{85}"]),
+ ("\u{1}\u{9}", &["\u{1}\u{9}"]), ("\u{1}\u{308}\u{9}", &["\u{1}\u{308}\u{9}"]),
+ ("\u{1}\u{61}", &["\u{1}\u{61}"]), ("\u{1}\u{308}\u{61}", &["\u{1}\u{308}\u{61}"]),
+ ("\u{1}\u{41}", &["\u{1}\u{41}"]), ("\u{1}\u{308}\u{41}", &["\u{1}\u{308}\u{41}"]),
+ ("\u{1}\u{1bb}", &["\u{1}\u{1bb}"]), ("\u{1}\u{308}\u{1bb}", &["\u{1}\u{308}\u{1bb}"]),
+ ("\u{1}\u{30}", &["\u{1}\u{30}"]), ("\u{1}\u{308}\u{30}", &["\u{1}\u{308}\u{30}"]),
+ ("\u{1}\u{2e}", &["\u{1}\u{2e}"]), ("\u{1}\u{308}\u{2e}", &["\u{1}\u{308}\u{2e}"]),
+ ("\u{1}\u{21}", &["\u{1}\u{21}"]), ("\u{1}\u{308}\u{21}", &["\u{1}\u{308}\u{21}"]),
+ ("\u{1}\u{22}", &["\u{1}\u{22}"]), ("\u{1}\u{308}\u{22}", &["\u{1}\u{308}\u{22}"]),
+ ("\u{1}\u{2c}", &["\u{1}\u{2c}"]), ("\u{1}\u{308}\u{2c}", &["\u{1}\u{308}\u{2c}"]),
+ ("\u{1}\u{ad}", &["\u{1}\u{ad}"]), ("\u{1}\u{308}\u{ad}", &["\u{1}\u{308}\u{ad}"]),
+ ("\u{1}\u{300}", &["\u{1}\u{300}"]), ("\u{1}\u{308}\u{300}", &["\u{1}\u{308}\u{300}"]),
+ ("\u{d}\u{1}", &["\u{d}", "\u{1}"]), ("\u{d}\u{308}\u{1}", &["\u{d}", "\u{308}\u{1}"]),
+ ("\u{d}\u{d}", &["\u{d}", "\u{d}"]), ("\u{d}\u{308}\u{d}", &["\u{d}", "\u{308}\u{d}"]),
+ ("\u{d}\u{a}", &["\u{d}\u{a}"]), ("\u{d}\u{308}\u{a}", &["\u{d}", "\u{308}\u{a}"]),
+ ("\u{d}\u{85}", &["\u{d}", "\u{85}"]), ("\u{d}\u{308}\u{85}", &["\u{d}", "\u{308}\u{85}"]),
+ ("\u{d}\u{9}", &["\u{d}", "\u{9}"]), ("\u{d}\u{308}\u{9}", &["\u{d}", "\u{308}\u{9}"]),
+ ("\u{d}\u{61}", &["\u{d}", "\u{61}"]), ("\u{d}\u{308}\u{61}", &["\u{d}", "\u{308}\u{61}"]),
+ ("\u{d}\u{41}", &["\u{d}", "\u{41}"]), ("\u{d}\u{308}\u{41}", &["\u{d}", "\u{308}\u{41}"]),
+ ("\u{d}\u{1bb}", &["\u{d}", "\u{1bb}"]), ("\u{d}\u{308}\u{1bb}", &["\u{d}",
+ "\u{308}\u{1bb}"]), ("\u{d}\u{30}", &["\u{d}", "\u{30}"]), ("\u{d}\u{308}\u{30}", &["\u{d}",
+ "\u{308}\u{30}"]), ("\u{d}\u{2e}", &["\u{d}", "\u{2e}"]), ("\u{d}\u{308}\u{2e}", &["\u{d}",
+ "\u{308}\u{2e}"]), ("\u{d}\u{21}", &["\u{d}", "\u{21}"]), ("\u{d}\u{308}\u{21}", &["\u{d}",
+ "\u{308}\u{21}"]), ("\u{d}\u{22}", &["\u{d}", "\u{22}"]), ("\u{d}\u{308}\u{22}", &["\u{d}",
+ "\u{308}\u{22}"]), ("\u{d}\u{2c}", &["\u{d}", "\u{2c}"]), ("\u{d}\u{308}\u{2c}", &["\u{d}",
+ "\u{308}\u{2c}"]), ("\u{d}\u{ad}", &["\u{d}", "\u{ad}"]), ("\u{d}\u{308}\u{ad}", &["\u{d}",
+ "\u{308}\u{ad}"]), ("\u{d}\u{300}", &["\u{d}", "\u{300}"]), ("\u{d}\u{308}\u{300}",
+ &["\u{d}", "\u{308}\u{300}"]), ("\u{a}\u{1}", &["\u{a}", "\u{1}"]), ("\u{a}\u{308}\u{1}",
+ &["\u{a}", "\u{308}\u{1}"]), ("\u{a}\u{d}", &["\u{a}", "\u{d}"]), ("\u{a}\u{308}\u{d}",
+ &["\u{a}", "\u{308}\u{d}"]), ("\u{a}\u{a}", &["\u{a}", "\u{a}"]), ("\u{a}\u{308}\u{a}",
+ &["\u{a}", "\u{308}\u{a}"]), ("\u{a}\u{85}", &["\u{a}", "\u{85}"]), ("\u{a}\u{308}\u{85}",
+ &["\u{a}", "\u{308}\u{85}"]), ("\u{a}\u{9}", &["\u{a}", "\u{9}"]), ("\u{a}\u{308}\u{9}",
+ &["\u{a}", "\u{308}\u{9}"]), ("\u{a}\u{61}", &["\u{a}", "\u{61}"]), ("\u{a}\u{308}\u{61}",
+ &["\u{a}", "\u{308}\u{61}"]), ("\u{a}\u{41}", &["\u{a}", "\u{41}"]), ("\u{a}\u{308}\u{41}",
+ &["\u{a}", "\u{308}\u{41}"]), ("\u{a}\u{1bb}", &["\u{a}", "\u{1bb}"]),
+ ("\u{a}\u{308}\u{1bb}", &["\u{a}", "\u{308}\u{1bb}"]), ("\u{a}\u{30}", &["\u{a}",
+ "\u{30}"]), ("\u{a}\u{308}\u{30}", &["\u{a}", "\u{308}\u{30}"]), ("\u{a}\u{2e}", &["\u{a}",
+ "\u{2e}"]), ("\u{a}\u{308}\u{2e}", &["\u{a}", "\u{308}\u{2e}"]), ("\u{a}\u{21}", &["\u{a}",
+ "\u{21}"]), ("\u{a}\u{308}\u{21}", &["\u{a}", "\u{308}\u{21}"]), ("\u{a}\u{22}", &["\u{a}",
+ "\u{22}"]), ("\u{a}\u{308}\u{22}", &["\u{a}", "\u{308}\u{22}"]), ("\u{a}\u{2c}", &["\u{a}",
+ "\u{2c}"]), ("\u{a}\u{308}\u{2c}", &["\u{a}", "\u{308}\u{2c}"]), ("\u{a}\u{ad}", &["\u{a}",
+ "\u{ad}"]), ("\u{a}\u{308}\u{ad}", &["\u{a}", "\u{308}\u{ad}"]), ("\u{a}\u{300}", &["\u{a}",
+ "\u{300}"]), ("\u{a}\u{308}\u{300}", &["\u{a}", "\u{308}\u{300}"]), ("\u{85}\u{1}",
+ &["\u{85}", "\u{1}"]), ("\u{85}\u{308}\u{1}", &["\u{85}", "\u{308}\u{1}"]), ("\u{85}\u{d}",
+ &["\u{85}", "\u{d}"]), ("\u{85}\u{308}\u{d}", &["\u{85}", "\u{308}\u{d}"]), ("\u{85}\u{a}",
+ &["\u{85}", "\u{a}"]), ("\u{85}\u{308}\u{a}", &["\u{85}", "\u{308}\u{a}"]), ("\u{85}\u{85}",
+ &["\u{85}", "\u{85}"]), ("\u{85}\u{308}\u{85}", &["\u{85}", "\u{308}\u{85}"]),
+ ("\u{85}\u{9}", &["\u{85}", "\u{9}"]), ("\u{85}\u{308}\u{9}", &["\u{85}", "\u{308}\u{9}"]),
+ ("\u{85}\u{61}", &["\u{85}", "\u{61}"]), ("\u{85}\u{308}\u{61}", &["\u{85}",
+ "\u{308}\u{61}"]), ("\u{85}\u{41}", &["\u{85}", "\u{41}"]), ("\u{85}\u{308}\u{41}",
+ &["\u{85}", "\u{308}\u{41}"]), ("\u{85}\u{1bb}", &["\u{85}", "\u{1bb}"]),
+ ("\u{85}\u{308}\u{1bb}", &["\u{85}", "\u{308}\u{1bb}"]), ("\u{85}\u{30}", &["\u{85}",
+ "\u{30}"]), ("\u{85}\u{308}\u{30}", &["\u{85}", "\u{308}\u{30}"]), ("\u{85}\u{2e}",
+ &["\u{85}", "\u{2e}"]), ("\u{85}\u{308}\u{2e}", &["\u{85}", "\u{308}\u{2e}"]),
+ ("\u{85}\u{21}", &["\u{85}", "\u{21}"]), ("\u{85}\u{308}\u{21}", &["\u{85}",
+ "\u{308}\u{21}"]), ("\u{85}\u{22}", &["\u{85}", "\u{22}"]), ("\u{85}\u{308}\u{22}",
+ &["\u{85}", "\u{308}\u{22}"]), ("\u{85}\u{2c}", &["\u{85}", "\u{2c}"]),
+ ("\u{85}\u{308}\u{2c}", &["\u{85}", "\u{308}\u{2c}"]), ("\u{85}\u{ad}", &["\u{85}",
+ "\u{ad}"]), ("\u{85}\u{308}\u{ad}", &["\u{85}", "\u{308}\u{ad}"]), ("\u{85}\u{300}",
+ &["\u{85}", "\u{300}"]), ("\u{85}\u{308}\u{300}", &["\u{85}", "\u{308}\u{300}"]),
+ ("\u{9}\u{1}", &["\u{9}\u{1}"]), ("\u{9}\u{308}\u{1}", &["\u{9}\u{308}\u{1}"]),
+ ("\u{9}\u{d}", &["\u{9}\u{d}"]), ("\u{9}\u{308}\u{d}", &["\u{9}\u{308}\u{d}"]),
+ ("\u{9}\u{a}", &["\u{9}\u{a}"]), ("\u{9}\u{308}\u{a}", &["\u{9}\u{308}\u{a}"]),
+ ("\u{9}\u{85}", &["\u{9}\u{85}"]), ("\u{9}\u{308}\u{85}", &["\u{9}\u{308}\u{85}"]),
+ ("\u{9}\u{9}", &["\u{9}\u{9}"]), ("\u{9}\u{308}\u{9}", &["\u{9}\u{308}\u{9}"]),
+ ("\u{9}\u{61}", &["\u{9}\u{61}"]), ("\u{9}\u{308}\u{61}", &["\u{9}\u{308}\u{61}"]),
+ ("\u{9}\u{41}", &["\u{9}\u{41}"]), ("\u{9}\u{308}\u{41}", &["\u{9}\u{308}\u{41}"]),
+ ("\u{9}\u{1bb}", &["\u{9}\u{1bb}"]), ("\u{9}\u{308}\u{1bb}", &["\u{9}\u{308}\u{1bb}"]),
+ ("\u{9}\u{30}", &["\u{9}\u{30}"]), ("\u{9}\u{308}\u{30}", &["\u{9}\u{308}\u{30}"]),
+ ("\u{9}\u{2e}", &["\u{9}\u{2e}"]), ("\u{9}\u{308}\u{2e}", &["\u{9}\u{308}\u{2e}"]),
+ ("\u{9}\u{21}", &["\u{9}\u{21}"]), ("\u{9}\u{308}\u{21}", &["\u{9}\u{308}\u{21}"]),
+ ("\u{9}\u{22}", &["\u{9}\u{22}"]), ("\u{9}\u{308}\u{22}", &["\u{9}\u{308}\u{22}"]),
+ ("\u{9}\u{2c}", &["\u{9}\u{2c}"]), ("\u{9}\u{308}\u{2c}", &["\u{9}\u{308}\u{2c}"]),
+ ("\u{9}\u{ad}", &["\u{9}\u{ad}"]), ("\u{9}\u{308}\u{ad}", &["\u{9}\u{308}\u{ad}"]),
+ ("\u{9}\u{300}", &["\u{9}\u{300}"]), ("\u{9}\u{308}\u{300}", &["\u{9}\u{308}\u{300}"]),
+ ("\u{61}\u{1}", &["\u{61}\u{1}"]), ("\u{61}\u{308}\u{1}", &["\u{61}\u{308}\u{1}"]),
+ ("\u{61}\u{d}", &["\u{61}\u{d}"]), ("\u{61}\u{308}\u{d}", &["\u{61}\u{308}\u{d}"]),
+ ("\u{61}\u{a}", &["\u{61}\u{a}"]), ("\u{61}\u{308}\u{a}", &["\u{61}\u{308}\u{a}"]),
+ ("\u{61}\u{85}", &["\u{61}\u{85}"]), ("\u{61}\u{308}\u{85}", &["\u{61}\u{308}\u{85}"]),
+ ("\u{61}\u{9}", &["\u{61}\u{9}"]), ("\u{61}\u{308}\u{9}", &["\u{61}\u{308}\u{9}"]),
+ ("\u{61}\u{61}", &["\u{61}\u{61}"]), ("\u{61}\u{308}\u{61}", &["\u{61}\u{308}\u{61}"]),
+ ("\u{61}\u{41}", &["\u{61}\u{41}"]), ("\u{61}\u{308}\u{41}", &["\u{61}\u{308}\u{41}"]),
+ ("\u{61}\u{1bb}", &["\u{61}\u{1bb}"]), ("\u{61}\u{308}\u{1bb}", &["\u{61}\u{308}\u{1bb}"]),
+ ("\u{61}\u{30}", &["\u{61}\u{30}"]), ("\u{61}\u{308}\u{30}", &["\u{61}\u{308}\u{30}"]),
+ ("\u{61}\u{2e}", &["\u{61}\u{2e}"]), ("\u{61}\u{308}\u{2e}", &["\u{61}\u{308}\u{2e}"]),
+ ("\u{61}\u{21}", &["\u{61}\u{21}"]), ("\u{61}\u{308}\u{21}", &["\u{61}\u{308}\u{21}"]),
+ ("\u{61}\u{22}", &["\u{61}\u{22}"]), ("\u{61}\u{308}\u{22}", &["\u{61}\u{308}\u{22}"]),
+ ("\u{61}\u{2c}", &["\u{61}\u{2c}"]), ("\u{61}\u{308}\u{2c}", &["\u{61}\u{308}\u{2c}"]),
+ ("\u{61}\u{ad}", &["\u{61}\u{ad}"]), ("\u{61}\u{308}\u{ad}", &["\u{61}\u{308}\u{ad}"]),
+ ("\u{61}\u{300}", &["\u{61}\u{300}"]), ("\u{61}\u{308}\u{300}", &["\u{61}\u{308}\u{300}"]),
+ ("\u{41}\u{1}", &["\u{41}\u{1}"]), ("\u{41}\u{308}\u{1}", &["\u{41}\u{308}\u{1}"]),
+ ("\u{41}\u{d}", &["\u{41}\u{d}"]), ("\u{41}\u{308}\u{d}", &["\u{41}\u{308}\u{d}"]),
+ ("\u{41}\u{a}", &["\u{41}\u{a}"]), ("\u{41}\u{308}\u{a}", &["\u{41}\u{308}\u{a}"]),
+ ("\u{41}\u{85}", &["\u{41}\u{85}"]), ("\u{41}\u{308}\u{85}", &["\u{41}\u{308}\u{85}"]),
+ ("\u{41}\u{9}", &["\u{41}\u{9}"]), ("\u{41}\u{308}\u{9}", &["\u{41}\u{308}\u{9}"]),
+ ("\u{41}\u{61}", &["\u{41}\u{61}"]), ("\u{41}\u{308}\u{61}", &["\u{41}\u{308}\u{61}"]),
+ ("\u{41}\u{41}", &["\u{41}\u{41}"]), ("\u{41}\u{308}\u{41}", &["\u{41}\u{308}\u{41}"]),
+ ("\u{41}\u{1bb}", &["\u{41}\u{1bb}"]), ("\u{41}\u{308}\u{1bb}", &["\u{41}\u{308}\u{1bb}"]),
+ ("\u{41}\u{30}", &["\u{41}\u{30}"]), ("\u{41}\u{308}\u{30}", &["\u{41}\u{308}\u{30}"]),
+ ("\u{41}\u{2e}", &["\u{41}\u{2e}"]), ("\u{41}\u{308}\u{2e}", &["\u{41}\u{308}\u{2e}"]),
+ ("\u{41}\u{21}", &["\u{41}\u{21}"]), ("\u{41}\u{308}\u{21}", &["\u{41}\u{308}\u{21}"]),
+ ("\u{41}\u{22}", &["\u{41}\u{22}"]), ("\u{41}\u{308}\u{22}", &["\u{41}\u{308}\u{22}"]),
+ ("\u{41}\u{2c}", &["\u{41}\u{2c}"]), ("\u{41}\u{308}\u{2c}", &["\u{41}\u{308}\u{2c}"]),
+ ("\u{41}\u{ad}", &["\u{41}\u{ad}"]), ("\u{41}\u{308}\u{ad}", &["\u{41}\u{308}\u{ad}"]),
+ ("\u{41}\u{300}", &["\u{41}\u{300}"]), ("\u{41}\u{308}\u{300}", &["\u{41}\u{308}\u{300}"]),
+ ("\u{1bb}\u{1}", &["\u{1bb}\u{1}"]), ("\u{1bb}\u{308}\u{1}", &["\u{1bb}\u{308}\u{1}"]),
+ ("\u{1bb}\u{d}", &["\u{1bb}\u{d}"]), ("\u{1bb}\u{308}\u{d}", &["\u{1bb}\u{308}\u{d}"]),
+ ("\u{1bb}\u{a}", &["\u{1bb}\u{a}"]), ("\u{1bb}\u{308}\u{a}", &["\u{1bb}\u{308}\u{a}"]),
+ ("\u{1bb}\u{85}", &["\u{1bb}\u{85}"]), ("\u{1bb}\u{308}\u{85}", &["\u{1bb}\u{308}\u{85}"]),
+ ("\u{1bb}\u{9}", &["\u{1bb}\u{9}"]), ("\u{1bb}\u{308}\u{9}", &["\u{1bb}\u{308}\u{9}"]),
+ ("\u{1bb}\u{61}", &["\u{1bb}\u{61}"]), ("\u{1bb}\u{308}\u{61}", &["\u{1bb}\u{308}\u{61}"]),
+ ("\u{1bb}\u{41}", &["\u{1bb}\u{41}"]), ("\u{1bb}\u{308}\u{41}", &["\u{1bb}\u{308}\u{41}"]),
+ ("\u{1bb}\u{1bb}", &["\u{1bb}\u{1bb}"]), ("\u{1bb}\u{308}\u{1bb}",
+ &["\u{1bb}\u{308}\u{1bb}"]), ("\u{1bb}\u{30}", &["\u{1bb}\u{30}"]), ("\u{1bb}\u{308}\u{30}",
+ &["\u{1bb}\u{308}\u{30}"]), ("\u{1bb}\u{2e}", &["\u{1bb}\u{2e}"]), ("\u{1bb}\u{308}\u{2e}",
+ &["\u{1bb}\u{308}\u{2e}"]), ("\u{1bb}\u{21}", &["\u{1bb}\u{21}"]), ("\u{1bb}\u{308}\u{21}",
+ &["\u{1bb}\u{308}\u{21}"]), ("\u{1bb}\u{22}", &["\u{1bb}\u{22}"]), ("\u{1bb}\u{308}\u{22}",
+ &["\u{1bb}\u{308}\u{22}"]), ("\u{1bb}\u{2c}", &["\u{1bb}\u{2c}"]), ("\u{1bb}\u{308}\u{2c}",
+ &["\u{1bb}\u{308}\u{2c}"]), ("\u{1bb}\u{ad}", &["\u{1bb}\u{ad}"]), ("\u{1bb}\u{308}\u{ad}",
+ &["\u{1bb}\u{308}\u{ad}"]), ("\u{1bb}\u{300}", &["\u{1bb}\u{300}"]),
+ ("\u{1bb}\u{308}\u{300}", &["\u{1bb}\u{308}\u{300}"]), ("\u{30}\u{1}", &["\u{30}\u{1}"]),
+ ("\u{30}\u{308}\u{1}", &["\u{30}\u{308}\u{1}"]), ("\u{30}\u{d}", &["\u{30}\u{d}"]),
+ ("\u{30}\u{308}\u{d}", &["\u{30}\u{308}\u{d}"]), ("\u{30}\u{a}", &["\u{30}\u{a}"]),
+ ("\u{30}\u{308}\u{a}", &["\u{30}\u{308}\u{a}"]), ("\u{30}\u{85}", &["\u{30}\u{85}"]),
+ ("\u{30}\u{308}\u{85}", &["\u{30}\u{308}\u{85}"]), ("\u{30}\u{9}", &["\u{30}\u{9}"]),
+ ("\u{30}\u{308}\u{9}", &["\u{30}\u{308}\u{9}"]), ("\u{30}\u{61}", &["\u{30}\u{61}"]),
+ ("\u{30}\u{308}\u{61}", &["\u{30}\u{308}\u{61}"]), ("\u{30}\u{41}", &["\u{30}\u{41}"]),
+ ("\u{30}\u{308}\u{41}", &["\u{30}\u{308}\u{41}"]), ("\u{30}\u{1bb}", &["\u{30}\u{1bb}"]),
+ ("\u{30}\u{308}\u{1bb}", &["\u{30}\u{308}\u{1bb}"]), ("\u{30}\u{30}", &["\u{30}\u{30}"]),
+ ("\u{30}\u{308}\u{30}", &["\u{30}\u{308}\u{30}"]), ("\u{30}\u{2e}", &["\u{30}\u{2e}"]),
+ ("\u{30}\u{308}\u{2e}", &["\u{30}\u{308}\u{2e}"]), ("\u{30}\u{21}", &["\u{30}\u{21}"]),
+ ("\u{30}\u{308}\u{21}", &["\u{30}\u{308}\u{21}"]), ("\u{30}\u{22}", &["\u{30}\u{22}"]),
+ ("\u{30}\u{308}\u{22}", &["\u{30}\u{308}\u{22}"]), ("\u{30}\u{2c}", &["\u{30}\u{2c}"]),
+ ("\u{30}\u{308}\u{2c}", &["\u{30}\u{308}\u{2c}"]), ("\u{30}\u{ad}", &["\u{30}\u{ad}"]),
+ ("\u{30}\u{308}\u{ad}", &["\u{30}\u{308}\u{ad}"]), ("\u{30}\u{300}", &["\u{30}\u{300}"]),
+ ("\u{30}\u{308}\u{300}", &["\u{30}\u{308}\u{300}"]), ("\u{2e}\u{1}", &["\u{2e}", "\u{1}"]),
+ ("\u{2e}\u{308}\u{1}", &["\u{2e}\u{308}", "\u{1}"]), ("\u{2e}\u{d}", &["\u{2e}\u{d}"]),
+ ("\u{2e}\u{308}\u{d}", &["\u{2e}\u{308}\u{d}"]), ("\u{2e}\u{a}", &["\u{2e}\u{a}"]),
+ ("\u{2e}\u{308}\u{a}", &["\u{2e}\u{308}\u{a}"]), ("\u{2e}\u{85}", &["\u{2e}\u{85}"]),
+ ("\u{2e}\u{308}\u{85}", &["\u{2e}\u{308}\u{85}"]), ("\u{2e}\u{9}", &["\u{2e}\u{9}"]),
+ ("\u{2e}\u{308}\u{9}", &["\u{2e}\u{308}\u{9}"]), ("\u{2e}\u{61}", &["\u{2e}\u{61}"]),
+ ("\u{2e}\u{308}\u{61}", &["\u{2e}\u{308}\u{61}"]), ("\u{2e}\u{41}", &["\u{2e}", "\u{41}"]),
+ ("\u{2e}\u{308}\u{41}", &["\u{2e}\u{308}", "\u{41}"]), ("\u{2e}\u{1bb}", &["\u{2e}",
+ "\u{1bb}"]), ("\u{2e}\u{308}\u{1bb}", &["\u{2e}\u{308}", "\u{1bb}"]), ("\u{2e}\u{30}",
+ &["\u{2e}\u{30}"]), ("\u{2e}\u{308}\u{30}", &["\u{2e}\u{308}\u{30}"]), ("\u{2e}\u{2e}",
+ &["\u{2e}\u{2e}"]), ("\u{2e}\u{308}\u{2e}", &["\u{2e}\u{308}\u{2e}"]), ("\u{2e}\u{21}",
+ &["\u{2e}\u{21}"]), ("\u{2e}\u{308}\u{21}", &["\u{2e}\u{308}\u{21}"]), ("\u{2e}\u{22}",
+ &["\u{2e}\u{22}"]), ("\u{2e}\u{308}\u{22}", &["\u{2e}\u{308}\u{22}"]), ("\u{2e}\u{2c}",
+ &["\u{2e}\u{2c}"]), ("\u{2e}\u{308}\u{2c}", &["\u{2e}\u{308}\u{2c}"]), ("\u{2e}\u{ad}",
+ &["\u{2e}\u{ad}"]), ("\u{2e}\u{308}\u{ad}", &["\u{2e}\u{308}\u{ad}"]), ("\u{2e}\u{300}",
+ &["\u{2e}\u{300}"]), ("\u{2e}\u{308}\u{300}", &["\u{2e}\u{308}\u{300}"]), ("\u{21}\u{1}",
+ &["\u{21}", "\u{1}"]), ("\u{21}\u{308}\u{1}", &["\u{21}\u{308}", "\u{1}"]), ("\u{21}\u{d}",
+ &["\u{21}\u{d}"]), ("\u{21}\u{308}\u{d}", &["\u{21}\u{308}\u{d}"]), ("\u{21}\u{a}",
+ &["\u{21}\u{a}"]), ("\u{21}\u{308}\u{a}", &["\u{21}\u{308}\u{a}"]), ("\u{21}\u{85}",
+ &["\u{21}\u{85}"]), ("\u{21}\u{308}\u{85}", &["\u{21}\u{308}\u{85}"]), ("\u{21}\u{9}",
+ &["\u{21}\u{9}"]), ("\u{21}\u{308}\u{9}", &["\u{21}\u{308}\u{9}"]), ("\u{21}\u{61}",
+ &["\u{21}", "\u{61}"]), ("\u{21}\u{308}\u{61}", &["\u{21}\u{308}", "\u{61}"]),
+ ("\u{21}\u{41}", &["\u{21}", "\u{41}"]), ("\u{21}\u{308}\u{41}", &["\u{21}\u{308}",
+ "\u{41}"]), ("\u{21}\u{1bb}", &["\u{21}", "\u{1bb}"]), ("\u{21}\u{308}\u{1bb}",
+ &["\u{21}\u{308}", "\u{1bb}"]), ("\u{21}\u{30}", &["\u{21}", "\u{30}"]),
+ ("\u{21}\u{308}\u{30}", &["\u{21}\u{308}", "\u{30}"]), ("\u{21}\u{2e}", &["\u{21}\u{2e}"]),
+ ("\u{21}\u{308}\u{2e}", &["\u{21}\u{308}\u{2e}"]), ("\u{21}\u{21}", &["\u{21}\u{21}"]),
+ ("\u{21}\u{308}\u{21}", &["\u{21}\u{308}\u{21}"]), ("\u{21}\u{22}", &["\u{21}\u{22}"]),
+ ("\u{21}\u{308}\u{22}", &["\u{21}\u{308}\u{22}"]), ("\u{21}\u{2c}", &["\u{21}\u{2c}"]),
+ ("\u{21}\u{308}\u{2c}", &["\u{21}\u{308}\u{2c}"]), ("\u{21}\u{ad}", &["\u{21}\u{ad}"]),
+ ("\u{21}\u{308}\u{ad}", &["\u{21}\u{308}\u{ad}"]), ("\u{21}\u{300}", &["\u{21}\u{300}"]),
+ ("\u{21}\u{308}\u{300}", &["\u{21}\u{308}\u{300}"]), ("\u{22}\u{1}", &["\u{22}\u{1}"]),
+ ("\u{22}\u{308}\u{1}", &["\u{22}\u{308}\u{1}"]), ("\u{22}\u{d}", &["\u{22}\u{d}"]),
+ ("\u{22}\u{308}\u{d}", &["\u{22}\u{308}\u{d}"]), ("\u{22}\u{a}", &["\u{22}\u{a}"]),
+ ("\u{22}\u{308}\u{a}", &["\u{22}\u{308}\u{a}"]), ("\u{22}\u{85}", &["\u{22}\u{85}"]),
+ ("\u{22}\u{308}\u{85}", &["\u{22}\u{308}\u{85}"]), ("\u{22}\u{9}", &["\u{22}\u{9}"]),
+ ("\u{22}\u{308}\u{9}", &["\u{22}\u{308}\u{9}"]), ("\u{22}\u{61}", &["\u{22}\u{61}"]),
+ ("\u{22}\u{308}\u{61}", &["\u{22}\u{308}\u{61}"]), ("\u{22}\u{41}", &["\u{22}\u{41}"]),
+ ("\u{22}\u{308}\u{41}", &["\u{22}\u{308}\u{41}"]), ("\u{22}\u{1bb}", &["\u{22}\u{1bb}"]),
+ ("\u{22}\u{308}\u{1bb}", &["\u{22}\u{308}\u{1bb}"]), ("\u{22}\u{30}", &["\u{22}\u{30}"]),
+ ("\u{22}\u{308}\u{30}", &["\u{22}\u{308}\u{30}"]), ("\u{22}\u{2e}", &["\u{22}\u{2e}"]),
+ ("\u{22}\u{308}\u{2e}", &["\u{22}\u{308}\u{2e}"]), ("\u{22}\u{21}", &["\u{22}\u{21}"]),
+ ("\u{22}\u{308}\u{21}", &["\u{22}\u{308}\u{21}"]), ("\u{22}\u{22}", &["\u{22}\u{22}"]),
+ ("\u{22}\u{308}\u{22}", &["\u{22}\u{308}\u{22}"]), ("\u{22}\u{2c}", &["\u{22}\u{2c}"]),
+ ("\u{22}\u{308}\u{2c}", &["\u{22}\u{308}\u{2c}"]), ("\u{22}\u{ad}", &["\u{22}\u{ad}"]),
+ ("\u{22}\u{308}\u{ad}", &["\u{22}\u{308}\u{ad}"]), ("\u{22}\u{300}", &["\u{22}\u{300}"]),
+ ("\u{22}\u{308}\u{300}", &["\u{22}\u{308}\u{300}"]), ("\u{2c}\u{1}", &["\u{2c}\u{1}"]),
+ ("\u{2c}\u{308}\u{1}", &["\u{2c}\u{308}\u{1}"]), ("\u{2c}\u{d}", &["\u{2c}\u{d}"]),
+ ("\u{2c}\u{308}\u{d}", &["\u{2c}\u{308}\u{d}"]), ("\u{2c}\u{a}", &["\u{2c}\u{a}"]),
+ ("\u{2c}\u{308}\u{a}", &["\u{2c}\u{308}\u{a}"]), ("\u{2c}\u{85}", &["\u{2c}\u{85}"]),
+ ("\u{2c}\u{308}\u{85}", &["\u{2c}\u{308}\u{85}"]), ("\u{2c}\u{9}", &["\u{2c}\u{9}"]),
+ ("\u{2c}\u{308}\u{9}", &["\u{2c}\u{308}\u{9}"]), ("\u{2c}\u{61}", &["\u{2c}\u{61}"]),
+ ("\u{2c}\u{308}\u{61}", &["\u{2c}\u{308}\u{61}"]), ("\u{2c}\u{41}", &["\u{2c}\u{41}"]),
+ ("\u{2c}\u{308}\u{41}", &["\u{2c}\u{308}\u{41}"]), ("\u{2c}\u{1bb}", &["\u{2c}\u{1bb}"]),
+ ("\u{2c}\u{308}\u{1bb}", &["\u{2c}\u{308}\u{1bb}"]), ("\u{2c}\u{30}", &["\u{2c}\u{30}"]),
+ ("\u{2c}\u{308}\u{30}", &["\u{2c}\u{308}\u{30}"]), ("\u{2c}\u{2e}", &["\u{2c}\u{2e}"]),
+ ("\u{2c}\u{308}\u{2e}", &["\u{2c}\u{308}\u{2e}"]), ("\u{2c}\u{21}", &["\u{2c}\u{21}"]),
+ ("\u{2c}\u{308}\u{21}", &["\u{2c}\u{308}\u{21}"]), ("\u{2c}\u{22}", &["\u{2c}\u{22}"]),
+ ("\u{2c}\u{308}\u{22}", &["\u{2c}\u{308}\u{22}"]), ("\u{2c}\u{2c}", &["\u{2c}\u{2c}"]),
+ ("\u{2c}\u{308}\u{2c}", &["\u{2c}\u{308}\u{2c}"]), ("\u{2c}\u{ad}", &["\u{2c}\u{ad}"]),
+ ("\u{2c}\u{308}\u{ad}", &["\u{2c}\u{308}\u{ad}"]), ("\u{2c}\u{300}", &["\u{2c}\u{300}"]),
+ ("\u{2c}\u{308}\u{300}", &["\u{2c}\u{308}\u{300}"]), ("\u{ad}\u{1}", &["\u{ad}\u{1}"]),
+ ("\u{ad}\u{308}\u{1}", &["\u{ad}\u{308}\u{1}"]), ("\u{ad}\u{d}", &["\u{ad}\u{d}"]),
+ ("\u{ad}\u{308}\u{d}", &["\u{ad}\u{308}\u{d}"]), ("\u{ad}\u{a}", &["\u{ad}\u{a}"]),
+ ("\u{ad}\u{308}\u{a}", &["\u{ad}\u{308}\u{a}"]), ("\u{ad}\u{85}", &["\u{ad}\u{85}"]),
+ ("\u{ad}\u{308}\u{85}", &["\u{ad}\u{308}\u{85}"]), ("\u{ad}\u{9}", &["\u{ad}\u{9}"]),
+ ("\u{ad}\u{308}\u{9}", &["\u{ad}\u{308}\u{9}"]), ("\u{ad}\u{61}", &["\u{ad}\u{61}"]),
+ ("\u{ad}\u{308}\u{61}", &["\u{ad}\u{308}\u{61}"]), ("\u{ad}\u{41}", &["\u{ad}\u{41}"]),
+ ("\u{ad}\u{308}\u{41}", &["\u{ad}\u{308}\u{41}"]), ("\u{ad}\u{1bb}", &["\u{ad}\u{1bb}"]),
+ ("\u{ad}\u{308}\u{1bb}", &["\u{ad}\u{308}\u{1bb}"]), ("\u{ad}\u{30}", &["\u{ad}\u{30}"]),
+ ("\u{ad}\u{308}\u{30}", &["\u{ad}\u{308}\u{30}"]), ("\u{ad}\u{2e}", &["\u{ad}\u{2e}"]),
+ ("\u{ad}\u{308}\u{2e}", &["\u{ad}\u{308}\u{2e}"]), ("\u{ad}\u{21}", &["\u{ad}\u{21}"]),
+ ("\u{ad}\u{308}\u{21}", &["\u{ad}\u{308}\u{21}"]), ("\u{ad}\u{22}", &["\u{ad}\u{22}"]),
+ ("\u{ad}\u{308}\u{22}", &["\u{ad}\u{308}\u{22}"]), ("\u{ad}\u{2c}", &["\u{ad}\u{2c}"]),
+ ("\u{ad}\u{308}\u{2c}", &["\u{ad}\u{308}\u{2c}"]), ("\u{ad}\u{ad}", &["\u{ad}\u{ad}"]),
+ ("\u{ad}\u{308}\u{ad}", &["\u{ad}\u{308}\u{ad}"]), ("\u{ad}\u{300}", &["\u{ad}\u{300}"]),
+ ("\u{ad}\u{308}\u{300}", &["\u{ad}\u{308}\u{300}"]), ("\u{300}\u{1}", &["\u{300}\u{1}"]),
+ ("\u{300}\u{308}\u{1}", &["\u{300}\u{308}\u{1}"]), ("\u{300}\u{d}", &["\u{300}\u{d}"]),
+ ("\u{300}\u{308}\u{d}", &["\u{300}\u{308}\u{d}"]), ("\u{300}\u{a}", &["\u{300}\u{a}"]),
+ ("\u{300}\u{308}\u{a}", &["\u{300}\u{308}\u{a}"]), ("\u{300}\u{85}", &["\u{300}\u{85}"]),
+ ("\u{300}\u{308}\u{85}", &["\u{300}\u{308}\u{85}"]), ("\u{300}\u{9}", &["\u{300}\u{9}"]),
+ ("\u{300}\u{308}\u{9}", &["\u{300}\u{308}\u{9}"]), ("\u{300}\u{61}", &["\u{300}\u{61}"]),
+ ("\u{300}\u{308}\u{61}", &["\u{300}\u{308}\u{61}"]), ("\u{300}\u{41}", &["\u{300}\u{41}"]),
+ ("\u{300}\u{308}\u{41}", &["\u{300}\u{308}\u{41}"]), ("\u{300}\u{1bb}",
+ &["\u{300}\u{1bb}"]), ("\u{300}\u{308}\u{1bb}", &["\u{300}\u{308}\u{1bb}"]),
+ ("\u{300}\u{30}", &["\u{300}\u{30}"]), ("\u{300}\u{308}\u{30}", &["\u{300}\u{308}\u{30}"]),
+ ("\u{300}\u{2e}", &["\u{300}\u{2e}"]), ("\u{300}\u{308}\u{2e}", &["\u{300}\u{308}\u{2e}"]),
+ ("\u{300}\u{21}", &["\u{300}\u{21}"]), ("\u{300}\u{308}\u{21}", &["\u{300}\u{308}\u{21}"]),
+ ("\u{300}\u{22}", &["\u{300}\u{22}"]), ("\u{300}\u{308}\u{22}", &["\u{300}\u{308}\u{22}"]),
+ ("\u{300}\u{2c}", &["\u{300}\u{2c}"]), ("\u{300}\u{308}\u{2c}", &["\u{300}\u{308}\u{2c}"]),
+ ("\u{300}\u{ad}", &["\u{300}\u{ad}"]), ("\u{300}\u{308}\u{ad}", &["\u{300}\u{308}\u{ad}"]),
+ ("\u{300}\u{300}", &["\u{300}\u{300}"]), ("\u{300}\u{308}\u{300}",
+ &["\u{300}\u{308}\u{300}"]), ("\u{d}\u{a}\u{61}\u{a}\u{308}", &["\u{d}\u{a}", "\u{61}\u{a}",
+ "\u{308}"]), ("\u{61}\u{308}", &["\u{61}\u{308}"]), ("\u{20}\u{200d}\u{646}",
+ &["\u{20}\u{200d}\u{646}"]), ("\u{646}\u{200d}\u{20}", &["\u{646}\u{200d}\u{20}"]),
+ ("\u{28}\u{22}\u{47}\u{6f}\u{2e}\u{22}\u{29}\u{20}\u{28}\u{48}\u{65}\u{20}\u{64}\u{69}\u{64}\u{2e}\u{29}",
+ &["\u{28}\u{22}\u{47}\u{6f}\u{2e}\u{22}\u{29}\u{20}",
+ "\u{28}\u{48}\u{65}\u{20}\u{64}\u{69}\u{64}\u{2e}\u{29}"]),
+ ("\u{28}\u{201c}\u{47}\u{6f}\u{3f}\u{201d}\u{29}\u{20}\u{28}\u{48}\u{65}\u{20}\u{64}\u{69}\u{64}\u{2e}\u{29}",
+ &["\u{28}\u{201c}\u{47}\u{6f}\u{3f}\u{201d}\u{29}\u{20}",
+ "\u{28}\u{48}\u{65}\u{20}\u{64}\u{69}\u{64}\u{2e}\u{29}"]),
+ ("\u{55}\u{2e}\u{53}\u{2e}\u{41}\u{300}\u{2e}\u{20}\u{69}\u{73}",
+ &["\u{55}\u{2e}\u{53}\u{2e}\u{41}\u{300}\u{2e}\u{20}\u{69}\u{73}"]),
+ ("\u{55}\u{2e}\u{53}\u{2e}\u{41}\u{300}\u{3f}\u{20}\u{48}\u{65}",
+ &["\u{55}\u{2e}\u{53}\u{2e}\u{41}\u{300}\u{3f}\u{20}", "\u{48}\u{65}"]),
+ ("\u{55}\u{2e}\u{53}\u{2e}\u{41}\u{300}\u{2e}",
+ &["\u{55}\u{2e}\u{53}\u{2e}\u{41}\u{300}\u{2e}"]), ("\u{33}\u{2e}\u{34}",
+ &["\u{33}\u{2e}\u{34}"]), ("\u{63}\u{2e}\u{64}", &["\u{63}\u{2e}\u{64}"]),
+ ("\u{43}\u{2e}\u{64}", &["\u{43}\u{2e}\u{64}"]), ("\u{63}\u{2e}\u{44}",
+ &["\u{63}\u{2e}\u{44}"]), ("\u{43}\u{2e}\u{44}", &["\u{43}\u{2e}\u{44}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{74}\u{68}\u{65}",
+ &["\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{74}\u{68}\u{65}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{54}\u{68}\u{65}",
+ &["\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}", "\u{54}\u{68}\u{65}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{2018}\u{28}\u{74}\u{68}\u{65}",
+ &["\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{2018}\u{28}\u{74}\u{68}\u{65}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{2018}\u{28}\u{54}\u{68}\u{65}",
+ &["\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}", "\u{2018}\u{28}\u{54}\u{68}\u{65}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{308}\u{74}\u{68}\u{65}",
+ &["\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{308}\u{74}\u{68}\u{65}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{308}\u{54}\u{68}\u{65}",
+ &["\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{a0}\u{308}", "\u{54}\u{68}\u{65}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{308}\u{54}\u{68}\u{65}",
+ &["\u{65}\u{74}\u{63}\u{2e}\u{29}\u{2019}\u{308}", "\u{54}\u{68}\u{65}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{29}\u{a}\u{308}\u{54}\u{68}\u{65}",
+ &["\u{65}\u{74}\u{63}\u{2e}\u{29}\u{a}", "\u{308}\u{54}\u{68}\u{65}"]),
+ ("\u{74}\u{68}\u{65}\u{20}\u{72}\u{65}\u{73}\u{70}\u{2e}\u{20}\u{6c}\u{65}\u{61}\u{64}\u{65}\u{72}\u{73}\u{20}\u{61}\u{72}\u{65}",
+ &["\u{74}\u{68}\u{65}\u{20}\u{72}\u{65}\u{73}\u{70}\u{2e}\u{20}\u{6c}\u{65}\u{61}\u{64}\u{65}\u{72}\u{73}\u{20}\u{61}\u{72}\u{65}"]),
+ ("\u{5b57}\u{2e}\u{5b57}", &["\u{5b57}\u{2e}", "\u{5b57}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{5b83}", &["\u{65}\u{74}\u{63}\u{2e}", "\u{5b83}"]),
+ ("\u{65}\u{74}\u{63}\u{2e}\u{3002}", &["\u{65}\u{74}\u{63}\u{2e}\u{3002}"]),
+ ("\u{5b57}\u{3002}\u{5b83}", &["\u{5b57}\u{3002}", "\u{5b83}"]), ("\u{21}\u{20}\u{20}",
+ &["\u{21}\u{20}\u{20}"]),
+ ("\u{2060}\u{28}\u{2060}\u{22}\u{2060}\u{47}\u{2060}\u{6f}\u{2060}\u{2e}\u{2060}\u{22}\u{2060}\u{29}\u{2060}\u{20}\u{2060}\u{28}\u{2060}\u{48}\u{2060}\u{65}\u{2060}\u{20}\u{2060}\u{64}\u{2060}\u{69}\u{2060}\u{64}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2060}",
+ &["\u{2060}\u{28}\u{2060}\u{22}\u{2060}\u{47}\u{2060}\u{6f}\u{2060}\u{2e}\u{2060}\u{22}\u{2060}\u{29}\u{2060}\u{20}\u{2060}",
+ "\u{28}\u{2060}\u{48}\u{2060}\u{65}\u{2060}\u{20}\u{2060}\u{64}\u{2060}\u{69}\u{2060}\u{64}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{28}\u{2060}\u{201c}\u{2060}\u{47}\u{2060}\u{6f}\u{2060}\u{3f}\u{2060}\u{201d}\u{2060}\u{29}\u{2060}\u{20}\u{2060}\u{28}\u{2060}\u{48}\u{2060}\u{65}\u{2060}\u{20}\u{2060}\u{64}\u{2060}\u{69}\u{2060}\u{64}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2060}",
+ &["\u{2060}\u{28}\u{2060}\u{201c}\u{2060}\u{47}\u{2060}\u{6f}\u{2060}\u{3f}\u{2060}\u{201d}\u{2060}\u{29}\u{2060}\u{20}\u{2060}",
+ "\u{28}\u{2060}\u{48}\u{2060}\u{65}\u{2060}\u{20}\u{2060}\u{64}\u{2060}\u{69}\u{2060}\u{64}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{55}\u{2060}\u{2e}\u{2060}\u{53}\u{2060}\u{2e}\u{2060}\u{41}\u{2060}\u{300}\u{2e}\u{2060}\u{20}\u{2060}\u{69}\u{2060}\u{73}\u{2060}\u{2060}",
+ &["\u{2060}\u{55}\u{2060}\u{2e}\u{2060}\u{53}\u{2060}\u{2e}\u{2060}\u{41}\u{2060}\u{300}\u{2e}\u{2060}\u{20}\u{2060}\u{69}\u{2060}\u{73}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{55}\u{2060}\u{2e}\u{2060}\u{53}\u{2060}\u{2e}\u{2060}\u{41}\u{2060}\u{300}\u{3f}\u{2060}\u{20}\u{2060}\u{48}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{55}\u{2060}\u{2e}\u{2060}\u{53}\u{2060}\u{2e}\u{2060}\u{41}\u{2060}\u{300}\u{3f}\u{2060}\u{20}\u{2060}",
+ "\u{48}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{55}\u{2060}\u{2e}\u{2060}\u{53}\u{2060}\u{2e}\u{2060}\u{41}\u{2060}\u{300}\u{2e}\u{2060}\u{2060}",
+ &["\u{2060}\u{55}\u{2060}\u{2e}\u{2060}\u{53}\u{2060}\u{2e}\u{2060}\u{41}\u{2060}\u{300}\u{2e}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{33}\u{2060}\u{2e}\u{2060}\u{34}\u{2060}\u{2060}",
+ &["\u{2060}\u{33}\u{2060}\u{2e}\u{2060}\u{34}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{64}\u{2060}\u{2060}",
+ &["\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{64}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{43}\u{2060}\u{2e}\u{2060}\u{64}\u{2060}\u{2060}",
+ &["\u{2060}\u{43}\u{2060}\u{2e}\u{2060}\u{64}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{44}\u{2060}\u{2060}",
+ &["\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{44}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{43}\u{2060}\u{2e}\u{2060}\u{44}\u{2060}\u{2060}",
+ &["\u{2060}\u{43}\u{2060}\u{2e}\u{2060}\u{44}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{74}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{74}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}",
+ "\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{2018}\u{2060}\u{28}\u{2060}\u{74}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{2018}\u{2060}\u{28}\u{2060}\u{74}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{2018}\u{2060}\u{28}\u{2060}\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}",
+ "\u{2018}\u{2060}\u{28}\u{2060}\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{308}\u{74}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{308}\u{74}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{308}\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{a0}\u{2060}\u{308}",
+ "\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{308}\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{2019}\u{2060}\u{308}",
+ "\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{a}\u{2060}\u{308}\u{2060}\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{29}\u{2060}\u{a}",
+ "\u{2060}\u{308}\u{2060}\u{54}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{74}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{20}\u{2060}\u{72}\u{2060}\u{65}\u{2060}\u{73}\u{2060}\u{70}\u{2060}\u{2e}\u{2060}\u{20}\u{2060}\u{6c}\u{2060}\u{65}\u{2060}\u{61}\u{2060}\u{64}\u{2060}\u{65}\u{2060}\u{72}\u{2060}\u{73}\u{2060}\u{20}\u{2060}\u{61}\u{2060}\u{72}\u{2060}\u{65}\u{2060}\u{2060}",
+ &["\u{2060}\u{74}\u{2060}\u{68}\u{2060}\u{65}\u{2060}\u{20}\u{2060}\u{72}\u{2060}\u{65}\u{2060}\u{73}\u{2060}\u{70}\u{2060}\u{2e}\u{2060}\u{20}\u{2060}\u{6c}\u{2060}\u{65}\u{2060}\u{61}\u{2060}\u{64}\u{2060}\u{65}\u{2060}\u{72}\u{2060}\u{73}\u{2060}\u{20}\u{2060}\u{61}\u{2060}\u{72}\u{2060}\u{65}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{5b57}\u{2060}\u{2e}\u{2060}\u{5b57}\u{2060}\u{2060}",
+ &["\u{2060}\u{5b57}\u{2060}\u{2e}\u{2060}", "\u{5b57}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{5b83}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}",
+ "\u{5b83}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{3002}\u{2060}\u{2060}",
+ &["\u{2060}\u{65}\u{2060}\u{74}\u{2060}\u{63}\u{2060}\u{2e}\u{2060}\u{3002}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{5b57}\u{2060}\u{3002}\u{2060}\u{5b83}\u{2060}\u{2060}",
+ &["\u{2060}\u{5b57}\u{2060}\u{3002}\u{2060}", "\u{5b83}\u{2060}\u{2060}"]),
+ ("\u{2060}\u{21}\u{2060}\u{20}\u{2060}\u{20}\u{2060}\u{2060}",
+ &["\u{2060}\u{21}\u{2060}\u{20}\u{2060}\u{20}\u{2060}\u{2060}"])
+ ];
+
diff --git a/unicode-segmentation/src/word.rs b/unicode-segmentation/src/word.rs
new file mode 100644
index 0000000..6e9c049
--- /dev/null
+++ b/unicode-segmentation/src/word.rs
@@ -0,0 +1,664 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::cmp;
+use core::iter::Filter;
+
+use tables::word::WordCat;
+
+/// An iterator over the substrings of a string which, after splitting the string on
+/// [word boundaries](http://www.unicode.org/reports/tr29/#Word_Boundaries),
+/// contain any characters with the
+/// [Alphabetic](http://unicode.org/reports/tr44/#Alphabetic)
+/// property, or with
+/// [General_Category=Number](http://unicode.org/reports/tr44/#General_Category_Values).
+pub struct UnicodeWords<'a> {
+ inner: Filter<UWordBounds<'a>, fn(&&str) -> bool>,
+}
+
+impl<'a> Iterator for UnicodeWords<'a> {
+ type Item = &'a str;
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a str> { self.inner.next() }
+}
+impl<'a> DoubleEndedIterator for UnicodeWords<'a> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() }
+}
+
+/// External iterator for a string's
+/// [word boundaries](http://www.unicode.org/reports/tr29/#Word_Boundaries).
+#[derive(Clone)]
+pub struct UWordBounds<'a> {
+ string: &'a str,
+ cat: Option<WordCat>,
+ catb: Option<WordCat>,
+}
+
+/// External iterator for word boundaries and byte offsets.
+#[derive(Clone)]
+pub struct UWordBoundIndices<'a> {
+ start_offset: usize,
+ iter: UWordBounds<'a>,
+}
+
+impl<'a> UWordBoundIndices<'a> {
+ #[inline]
+ /// View the underlying data (the part yet to be iterated) as a slice of the original string.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::UnicodeSegmentation;
+ /// let mut iter = "Hello world".split_word_bound_indices();
+ /// assert_eq!(iter.as_str(), "Hello world");
+ /// iter.next();
+ /// assert_eq!(iter.as_str(), " world");
+ /// iter.next();
+ /// assert_eq!(iter.as_str(), "world");
+ /// ```
+ pub fn as_str(&self) -> &'a str {
+ self.iter.as_str()
+ }
+}
+
+impl<'a> Iterator for UWordBoundIndices<'a> {
+ type Item = (usize, &'a str);
+
+ #[inline]
+ fn next(&mut self) -> Option<(usize, &'a str)> {
+ self.iter.next().map(|s| (s.as_ptr() as usize - self.start_offset, s))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl<'a> DoubleEndedIterator for UWordBoundIndices<'a> {
+ #[inline]
+ fn next_back(&mut self) -> Option<(usize, &'a str)> {
+ self.iter.next_back().map(|s| (s.as_ptr() as usize - self.start_offset, s))
+ }
+}
+
+// state machine for word boundary rules
+#[derive(Clone,Copy,PartialEq,Eq,Debug)]
+enum UWordBoundsState {
+ Start,
+ Letter,
+ HLetter,
+ Numeric,
+ Katakana,
+ ExtendNumLet,
+ Regional(RegionalState),
+ FormatExtend(FormatExtendType),
+ Zwj,
+ Emoji,
+ WSegSpace,
+}
+
+// subtypes for FormatExtend state in UWordBoundsState
+#[derive(Clone,Copy,PartialEq,Eq,Debug)]
+enum FormatExtendType {
+ AcceptAny,
+ AcceptNone,
+ RequireLetter,
+ RequireHLetter,
+ AcceptQLetter,
+ RequireNumeric,
+}
+
+#[derive(Clone,Copy,PartialEq,Eq,Debug)]
+enum RegionalState {
+ Half,
+ Full,
+ Unknown,
+}
+
+fn is_emoji(ch: char) -> bool {
+ use tables::emoji;
+ emoji::emoji_category(ch) == emoji::EmojiCat::EC_Extended_Pictographic
+}
+
+impl<'a> Iterator for UWordBounds<'a> {
+ type Item = &'a str;
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let slen = self.string.len();
+ (cmp::min(slen, 1), Some(slen))
+ }
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a str> {
+ use self::UWordBoundsState::*;
+ use self::FormatExtendType::*;
+ use tables::word as wd;
+ if self.string.len() == 0 {
+ return None;
+ }
+
+ let mut take_curr = true;
+ let mut take_cat = true;
+ let mut idx = 0;
+ let mut saveidx = 0;
+ let mut state = Start;
+ let mut cat = wd::WC_Any;
+ let mut savecat = wd::WC_Any;
+
+ // Whether or not the previous category was ZWJ
+ // ZWJs get collapsed, so this handles precedence of WB3c over WB4
+ let mut prev_zwj;
+ // If extend/format/zwj were skipped. Handles precedence of WB3d over WB4
+ let mut skipped_format_extend = false;
+ for (curr, ch) in self.string.char_indices() {
+ idx = curr;
+ prev_zwj = cat == wd::WC_ZWJ;
+ // if there's a category cached, grab it
+ cat = match self.cat {
+ None => wd::word_category(ch),
+ _ => self.cat.take().unwrap()
+ };
+ take_cat = true;
+
+ // handle rule WB4
+ // just skip all format, extend, and zwj chars
+ // note that Start is a special case: if there's a bunch of Format | Extend
+ // characters at the beginning of a block of text, dump them out as one unit.
+ //
+ // (This is not obvious from the wording of UAX#29, but if you look at the
+ // test cases http://www.unicode.org/Public/UNIDATA/auxiliary/WordBreakTest.txt
+ // then the "correct" interpretation of WB4 becomes apparent.)
+ if state != Start {
+ match cat {
+ wd::WC_Extend | wd::WC_Format | wd::WC_ZWJ => {
+ skipped_format_extend = true;
+ continue
+ }
+ _ => {}
+ }
+ }
+
+ // rule WB3c
+ // WB4 makes all ZWJs collapse into the previous state
+ // but you can still be in a Zwj state if you started with Zwj
+ //
+ // This means that an EP + Zwj will collapse into EP, which is wrong,
+ // since EP+EP is not a boundary but EP+ZWJ+EP is
+ //
+ // Thus, we separately keep track of whether or not the last character
+ // was a ZWJ. This is an additional bit of state tracked outside of the
+ // state enum; the state enum represents the last non-zwj state encountered.
+ // When prev_zwj is true, for the purposes of WB3c, we are in the Zwj state,
+ // however we are in the previous state for the purposes of all other rules.
+ if prev_zwj {
+ if is_emoji(ch) {
+ state = Emoji;
+ continue;
+ }
+ }
+ // Don't use `continue` in this match without updating `cat`
+ state = match state {
+ Start if cat == wd::WC_CR => {
+ idx += match self.get_next_cat(idx) {
+ Some(ncat) if ncat == wd::WC_LF => 1, // rule WB3
+ _ => 0
+ };
+ break; // rule WB3a
+ },
+ Start => match cat {
+ wd::WC_ALetter => Letter, // rule WB5, WB6, WB9, WB13a
+ wd::WC_Hebrew_Letter => HLetter, // rule WB5, WB6, WB7a, WB7b, WB9, WB13a
+ wd::WC_Numeric => Numeric, // rule WB8, WB10, WB12, WB13a
+ wd::WC_Katakana => Katakana, // rule WB13, WB13a
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13a, WB13b
+ wd::WC_Regional_Indicator => Regional(RegionalState::Half), // rule WB13c
+ wd::WC_LF | wd::WC_Newline => break, // rule WB3a
+ wd::WC_ZWJ => Zwj, // rule WB3c
+ wd::WC_WSegSpace => WSegSpace, // rule WB3d
+ _ => {
+ if let Some(ncat) = self.get_next_cat(idx) { // rule WB4
+ if ncat == wd::WC_Format || ncat == wd::WC_Extend || ncat == wd::WC_ZWJ {
+ state = FormatExtend(AcceptNone);
+ self.cat = Some(ncat);
+ continue;
+ }
+ }
+ break; // rule WB999
+ }
+ },
+ WSegSpace => match cat {
+ wd::WC_WSegSpace if !skipped_format_extend => WSegSpace,
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Zwj => {
+ // We already handle WB3c above.
+ take_curr = false;
+ break;
+ }
+ Letter | HLetter => match cat {
+ wd::WC_ALetter => Letter, // rule WB5
+ wd::WC_Hebrew_Letter => HLetter, // rule WB5
+ wd::WC_Numeric => Numeric, // rule WB9
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13a
+ wd::WC_Double_Quote if state == HLetter => {
+ savecat = cat;
+ saveidx = idx;
+ FormatExtend(RequireHLetter) // rule WB7b
+ },
+ wd::WC_Single_Quote if state == HLetter => {
+ FormatExtend(AcceptQLetter) // rule WB7a
+ },
+ wd::WC_MidLetter | wd::WC_MidNumLet | wd::WC_Single_Quote => {
+ savecat = cat;
+ saveidx = idx;
+ FormatExtend(RequireLetter) // rule WB6
+ },
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Numeric => match cat {
+ wd::WC_Numeric => Numeric, // rule WB8
+ wd::WC_ALetter => Letter, // rule WB10
+ wd::WC_Hebrew_Letter => HLetter, // rule WB10
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13a
+ wd::WC_MidNum | wd::WC_MidNumLet | wd::WC_Single_Quote => {
+ savecat = cat;
+ saveidx = idx;
+ FormatExtend(RequireNumeric) // rule WB12
+ },
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Katakana => match cat {
+ wd::WC_Katakana => Katakana, // rule WB13
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13a
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ ExtendNumLet => match cat {
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13a
+ wd::WC_ALetter => Letter, // rule WB13b
+ wd::WC_Hebrew_Letter => HLetter, // rule WB13b
+ wd::WC_Numeric => Numeric, // rule WB13b
+ wd::WC_Katakana => Katakana, // rule WB13b
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Regional(RegionalState::Full) => {
+ // if it reaches here we've gone too far,
+ // a full flag can only compose with ZWJ/Extend/Format
+ // proceeding it.
+ take_curr = false;
+ break;
+ }
+ Regional(RegionalState::Half) => match cat {
+ wd::WC_Regional_Indicator => Regional(RegionalState::Full), // rule WB13c
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Regional(_) => unreachable!("RegionalState::Unknown should not occur on forward iteration"),
+ Emoji => {
+ // We already handle WB3c above. If you've reached this point, the emoji sequence is over.
+ take_curr = false;
+ break;
+ },
+ FormatExtend(t) => match t { // handle FormatExtends depending on what type
+ RequireNumeric if cat == wd::WC_Numeric => Numeric, // rule WB11
+ RequireLetter | AcceptQLetter if cat == wd::WC_ALetter => Letter, // rule WB7
+ RequireLetter | AcceptQLetter if cat == wd::WC_Hebrew_Letter => HLetter, // WB7a
+ RequireHLetter if cat == wd::WC_Hebrew_Letter => HLetter, // rule WB7b
+ AcceptNone | AcceptQLetter => {
+ take_curr = false; // emit all the Format|Extend characters
+ take_cat = false;
+ break;
+ },
+ _ => break // rewind (in if statement below)
+ }
+ }
+ }
+
+ if let FormatExtend(t) = state {
+ // we were looking for something and didn't find it; we have to back up
+ if t == RequireLetter || t == RequireHLetter || t == RequireNumeric {
+ idx = saveidx;
+ cat = savecat;
+ take_curr = false;
+ }
+ }
+
+ self.cat = if take_curr {
+ idx = idx + self.string[idx..].chars().next().unwrap().len_utf8();
+ None
+ } else if take_cat {
+ Some(cat)
+ } else {
+ None
+ };
+
+ let retstr = &self.string[..idx];
+ self.string = &self.string[idx..];
+ Some(retstr)
+ }
+}
+
+impl<'a> DoubleEndedIterator for UWordBounds<'a> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a str> {
+ use self::UWordBoundsState::*;
+ use self::FormatExtendType::*;
+ use tables::word as wd;
+ if self.string.len() == 0 {
+ return None;
+ }
+
+ let mut take_curr = true;
+ let mut take_cat = true;
+ let mut idx = self.string.len();
+ idx -= self.string.chars().next_back().unwrap().len_utf8();
+ let mut previdx = idx;
+ let mut saveidx = idx;
+ let mut state = Start;
+ let mut savestate = Start;
+ let mut cat = wd::WC_Any;
+
+ let mut skipped_format_extend = false;
+
+ for (curr, ch) in self.string.char_indices().rev() {
+ previdx = idx;
+ idx = curr;
+
+ // if there's a category cached, grab it
+ cat = match self.catb {
+ None => wd::word_category(ch),
+ _ => self.catb.take().unwrap()
+ };
+ take_cat = true;
+
+ // backward iterator over word boundaries. Mostly the same as the forward
+ // iterator, with two weirdnesses:
+ // (1) If we encounter a single quote in the Start state, we have to check for a
+ // Hebrew Letter immediately before it.
+ // (2) Format and Extend char handling takes some gymnastics.
+
+ if cat == wd::WC_Extend
+ || cat == wd::WC_Format
+ || (cat == wd::WC_ZWJ && state != Zwj) { // WB3c has more priority so we should not
+ // fold in that case
+ if match state {
+ FormatExtend(_) | Start => false,
+ _ => true
+ } {
+ saveidx = previdx;
+ savestate = state;
+ state = FormatExtend(AcceptNone);
+ }
+
+ if state != Start {
+ continue;
+ }
+ } else if state == FormatExtend(AcceptNone) {
+ // finished a scan of some Format|Extend chars, restore previous state
+ state = savestate;
+ previdx = saveidx;
+ take_cat = false;
+ skipped_format_extend = true;
+ }
+
+ // Don't use `continue` in this match without updating `catb`
+ state = match state {
+ Start | FormatExtend(AcceptAny) => match cat {
+ _ if is_emoji(ch) => Zwj,
+ wd::WC_ALetter => Letter, // rule WB5, WB7, WB10, WB13b
+ wd::WC_Hebrew_Letter => HLetter, // rule WB5, WB7, WB7c, WB10, WB13b
+ wd::WC_Numeric => Numeric, // rule WB8, WB9, WB11, WB13b
+ wd::WC_Katakana => Katakana, // rule WB13, WB13b
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13a
+ wd::WC_Regional_Indicator => Regional(RegionalState::Unknown), // rule WB13c
+ // rule WB4:
+ wd::WC_Extend | wd::WC_Format | wd::WC_ZWJ => FormatExtend(AcceptAny),
+ wd::WC_Single_Quote => {
+ saveidx = idx;
+ FormatExtend(AcceptQLetter) // rule WB7a
+ },
+ wd::WC_WSegSpace => WSegSpace,
+ wd::WC_CR | wd::WC_LF | wd::WC_Newline => {
+ if state == Start {
+ if cat == wd::WC_LF {
+ idx -= match self.get_prev_cat(idx) {
+ Some(pcat) if pcat == wd::WC_CR => 1, // rule WB3
+ _ => 0
+ };
+ }
+ } else {
+ take_curr = false;
+ }
+ break; // rule WB3a
+ },
+ _ => break // rule WB999
+ },
+ Zwj => match cat { // rule WB3c
+ wd::WC_ZWJ => {
+ FormatExtend(AcceptAny)
+ }
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ WSegSpace => match cat { // rule WB3d
+ wd::WC_WSegSpace if !skipped_format_extend => {
+ WSegSpace
+ }
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Letter | HLetter => match cat {
+ wd::WC_ALetter => Letter, // rule WB5
+ wd::WC_Hebrew_Letter => HLetter, // rule WB5
+ wd::WC_Numeric => Numeric, // rule WB10
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13b
+ wd::WC_Double_Quote if state == HLetter => {
+ saveidx = previdx;
+ FormatExtend(RequireHLetter) // rule WB7c
+ },
+ wd::WC_MidLetter | wd::WC_MidNumLet | wd::WC_Single_Quote => {
+ saveidx = previdx;
+ FormatExtend(RequireLetter) // rule WB7
+ },
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Numeric => match cat {
+ wd::WC_Numeric => Numeric, // rule WB8
+ wd::WC_ALetter => Letter, // rule WB9
+ wd::WC_Hebrew_Letter => HLetter, // rule WB9
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13b
+ wd::WC_MidNum | wd::WC_MidNumLet | wd::WC_Single_Quote => {
+ saveidx = previdx;
+ FormatExtend(RequireNumeric) // rule WB11
+ },
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Katakana => match cat {
+ wd::WC_Katakana => Katakana, // rule WB13
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13b
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ ExtendNumLet => match cat {
+ wd::WC_ExtendNumLet => ExtendNumLet, // rule WB13a
+ wd::WC_ALetter => Letter, // rule WB13a
+ wd::WC_Hebrew_Letter => HLetter, // rule WB13a
+ wd::WC_Numeric => Numeric, // rule WB13a
+ wd::WC_Katakana => Katakana, // rule WB13a
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Regional(mut regional_state) => match cat {
+ // rule WB13c
+ wd::WC_Regional_Indicator => {
+ if regional_state == RegionalState::Unknown {
+ let count = self.string[..previdx]
+ .chars().rev()
+ .map(|c| wd::word_category(c))
+ .filter(|&c| ! (c == wd::WC_ZWJ || c == wd::WC_Extend || c == wd::WC_Format))
+ .take_while(|&c| c == wd::WC_Regional_Indicator)
+ .count();
+ regional_state = if count % 2 == 0 {
+ RegionalState::Full
+ } else {
+ RegionalState::Half
+ };
+ }
+ if regional_state == RegionalState::Full {
+ take_curr = false;
+ break;
+ } else {
+ Regional(RegionalState::Full)
+ }
+ }
+ _ => {
+ take_curr = false;
+ break;
+ }
+ },
+ Emoji => {
+ if is_emoji(ch) { // rule WB3c
+ Zwj
+ } else {
+ take_curr = false;
+ break;
+ }
+ },
+ FormatExtend(t) => match t {
+ RequireNumeric if cat == wd::WC_Numeric => Numeric, // rule WB12
+ RequireLetter if cat == wd::WC_ALetter => Letter, // rule WB6
+ RequireLetter if cat == wd::WC_Hebrew_Letter => HLetter, // rule WB6
+ AcceptQLetter if cat == wd::WC_Hebrew_Letter => HLetter, // rule WB7a
+ RequireHLetter if cat == wd::WC_Hebrew_Letter => HLetter, // rule WB7b
+ _ => break // backtrack will happens
+ }
+ }
+ }
+
+ if let FormatExtend(t) = state {
+ // if we required something but didn't find it, backtrack
+ if t == RequireLetter || t == RequireHLetter ||
+ t == RequireNumeric || t == AcceptNone || t == AcceptQLetter {
+ previdx = saveidx;
+ take_cat = false;
+ take_curr = false;
+ }
+ }
+
+ self.catb = if take_curr {
+ None
+ } else {
+ idx = previdx;
+ if take_cat {
+ Some(cat)
+ } else {
+ None
+ }
+ };
+
+ let retstr = &self.string[idx..];
+ self.string = &self.string[..idx];
+ Some(retstr)
+ }
+}
+
+impl<'a> UWordBounds<'a> {
+ #[inline]
+ /// View the underlying data (the part yet to be iterated) as a slice of the original string.
+ ///
+ /// ```rust
+ /// # use unicode_segmentation::UnicodeSegmentation;
+ /// let mut iter = "Hello world".split_word_bounds();
+ /// assert_eq!(iter.as_str(), "Hello world");
+ /// iter.next();
+ /// assert_eq!(iter.as_str(), " world");
+ /// iter.next();
+ /// assert_eq!(iter.as_str(), "world");
+ /// ```
+ pub fn as_str(&self) -> &'a str {
+ self.string
+ }
+
+ #[inline]
+ fn get_next_cat(&self, idx: usize) -> Option<WordCat> {
+ use tables::word as wd;
+ let nidx = idx + self.string[idx..].chars().next().unwrap().len_utf8();
+ if nidx < self.string.len() {
+ let nch = self.string[nidx..].chars().next().unwrap();
+ Some(wd::word_category(nch))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn get_prev_cat(&self, idx: usize) -> Option<WordCat> {
+ use tables::word as wd;
+ if idx > 0 {
+ let nch = self.string[..idx].chars().next_back().unwrap();
+ Some(wd::word_category(nch))
+ } else {
+ None
+ }
+ }
+}
+
+#[inline]
+pub fn new_word_bounds<'b>(s: &'b str) -> UWordBounds<'b> {
+ UWordBounds { string: s, cat: None, catb: None }
+}
+
+#[inline]
+pub fn new_word_bound_indices<'b>(s: &'b str) -> UWordBoundIndices<'b> {
+ UWordBoundIndices { start_offset: s.as_ptr() as usize, iter: new_word_bounds(s) }
+}
+
+#[inline]
+pub fn new_unicode_words<'b>(s: &'b str) -> UnicodeWords<'b> {
+ use super::UnicodeSegmentation;
+ use tables::util::is_alphanumeric;
+
+ fn has_alphanumeric(s: &&str) -> bool { s.chars().any(|c| is_alphanumeric(c)) }
+ let has_alphanumeric: fn(&&str) -> bool = has_alphanumeric; // coerce to fn pointer
+
+ UnicodeWords { inner: s.split_word_bounds().filter(has_alphanumeric) }
+}
diff --git a/unicode-width/.gitignore b/unicode-width/.gitignore
new file mode 100644
index 0000000..5cdcdba
--- /dev/null
+++ b/unicode-width/.gitignore
@@ -0,0 +1,3 @@
+target
+Cargo.lock
+scripts/tmp
diff --git a/unicode-width/.travis.yml b/unicode-width/.travis.yml
new file mode 100644
index 0000000..64196fa
--- /dev/null
+++ b/unicode-width/.travis.yml
@@ -0,0 +1,28 @@
+language: rust
+rust: 'nightly'
+sudo: false
+script:
+ - cargo build --verbose --features bench
+ - cargo test --verbose --features bench
+ - cargo bench --verbose --features bench
+ - cargo clean
+ - cargo build --verbose
+ - cargo test --verbose
+# next line is an ugly hack to fix an annoying bug where rustdoc tries to use the rustc_private unicode_width crate
+# (there is probably a better fix than this)
+ - rm $(find /home/travis/.rustup -type f -name 'libunicode_width*')
+ - rustdoc --test README.md -L target/debug -L target/debug/deps
+ - cargo doc
+after_success: |
+ [ $TRAVIS_BRANCH = master ] &&
+ [ $TRAVIS_PULL_REQUEST = false ] &&
+ echo '<meta http-equiv=refresh content=0;url=unicode_width/index.html>' > target/doc/index.html &&
+ pip install ghp-import --user $USER &&
+ $HOME/.local/bin/ghp-import -n target/doc &&
+ git push -qf https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
+env:
+ global:
+ secure: vHL3zrN8AF+H79jrB8OfzuPqsUHevo6ECzwqXPj2dMSqcSXEeCY/ENAfiyFg+oW8yEVP8X2BS1a/C9yvVQRLqLbm1HbZ/5vUpoggT9S0IhKqZMyAcLYXfIEUDMDQuaSdFndDaHvq8275ScgX1LRv1kcPjQoZHuaXWMH8y/Suvyo=
+notifications:
+ email:
+ on_success: never
diff --git a/unicode-width/COPYRIGHT b/unicode-width/COPYRIGHT
new file mode 100644
index 0000000..b286ec1
--- /dev/null
+++ b/unicode-width/COPYRIGHT
@@ -0,0 +1,7 @@
+Licensed under the Apache License, Version 2.0
+<LICENSE-APACHE or
+http://www.apache.org/licenses/LICENSE-2.0> or the MIT
+license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
+at your option. All files in the project carrying such
+notice may not be copied, modified, or distributed except
+according to those terms.
diff --git a/unicode-width/Cargo.toml b/unicode-width/Cargo.toml
new file mode 100644
index 0000000..35228f2
--- /dev/null
+++ b/unicode-width/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+
+name = "unicode-width"
+version = "0.1.7"
+authors = ["kwantam <kwantam@gmail.com>", "Manish Goregaokar <manishsmail@gmail.com>"]
+
+homepage = "https://github.com/unicode-rs/unicode-width"
+repository = "https://github.com/unicode-rs/unicode-width"
+documentation = "https://unicode-rs.github.io/unicode-width"
+license = "MIT/Apache-2.0"
+keywords = ["text", "width", "unicode"]
+readme = "README.md"
+description = """
+Determine displayed width of `char` and `str` types
+according to Unicode Standard Annex #11 rules.
+"""
+
+exclude = [ "target/*", "Cargo.lock" ]
+
+[dependencies]
+std = { version = "1.0", package = "rustc-std-workspace-std", optional = true }
+core = { version = "1.0", package = "rustc-std-workspace-core", optional = true }
+compiler_builtins = { version = "0.1", optional = true }
+
+[features]
+default = []
+no_std = []
+bench = []
+rustc-dep-of-std = ['std', 'core', 'compiler_builtins']
diff --git a/unicode-width/LICENSE-APACHE b/unicode-width/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/unicode-width/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/unicode-width/LICENSE-MIT b/unicode-width/LICENSE-MIT
new file mode 100644
index 0000000..e69282e
--- /dev/null
+++ b/unicode-width/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015 The Rust Project Developers
+
+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/unicode-width/README.md b/unicode-width/README.md
new file mode 100644
index 0000000..595e163
--- /dev/null
+++ b/unicode-width/README.md
@@ -0,0 +1,58 @@
+# unicode-width
+
+Determine displayed width of `char` and `str` types according to
+[Unicode Standard Annex #11][UAX11] rules.
+
+[UAX11]: http://www.unicode.org/reports/tr11/
+
+[![Build Status](https://travis-ci.org/unicode-rs/unicode-width.svg)](https://travis-ci.org/unicode-rs/unicode-width)
+
+[Documentation](https://unicode-rs.github.io/unicode-width/unicode_width/index.html)
+
+```rust
+extern crate unicode_width;
+
+use unicode_width::UnicodeWidthStr;
+
+fn main() {
+ let teststr = "Hello, world!";
+ let width = UnicodeWidthStr::width(teststr);
+ println!("{}", teststr);
+ println!("The above string is {} columns wide.", width);
+ let width = teststr.width_cjk();
+ println!("The above string is {} columns wide (CJK).", width);
+}
+```
+
+**NOTE:** The computed width values may not match the actual rendered column
+width. For example, the woman scientist emoji comprises of a woman emoji, a
+zero-width joiner and a microscope emoji.
+
+```rust
+extern crate unicode_width;
+use unicode_width::UnicodeWidthStr;
+
+fn main() {
+ assert_eq!(UnicodeWidthStr::width("👩"), 2); // Woman
+ assert_eq!(UnicodeWidthStr::width("🔬"), 2); // Microscope
+ assert_eq!(UnicodeWidthStr::width("👩‍🔬"), 4); // Woman scientist
+}
+```
+
+See [Unicode Standard Annex #11][UAX11] for precise details on what is and isn't
+covered by this crate.
+
+## features
+
+unicode-width does not depend on libstd, so it can be used in crates
+with the `#![no_std]` attribute.
+
+## crates.io
+
+You can use this package in your project by adding the following
+to your `Cargo.toml`:
+
+```toml
+[dependencies]
+unicode-width = "0.1.7"
+```
diff --git a/unicode-width/scripts/unicode.py b/unicode-width/scripts/unicode.py
new file mode 100755
index 0000000..5456ee3
--- /dev/null
+++ b/unicode-width/scripts/unicode.py
@@ -0,0 +1,321 @@
+#!/usr/bin/env python3
+#
+# Copyright 2011-2015 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+# This script uses the following Unicode tables:
+# - EastAsianWidth.txt
+# - ReadMe.txt
+# - UnicodeData.txt
+#
+# Since this should not require frequent updates, we just store this
+# out-of-line and check the unicode.rs file into git.
+
+import fileinput, re, os, sys, operator
+
+preamble = '''// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly
+
+#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
+'''
+
+# Mapping taken from Table 12 from:
+# http://www.unicode.org/reports/tr44/#General_Category_Values
+expanded_categories = {
+ 'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'],
+ 'Lm': ['L'], 'Lo': ['L'],
+ 'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'],
+ 'Nd': ['N'], 'Nl': ['N'], 'No': ['No'],
+ 'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'],
+ 'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'],
+ 'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'],
+ 'Zs': ['Z'], 'Zl': ['Z'], 'Zp': ['Z'],
+ 'Cc': ['C'], 'Cf': ['C'], 'Cs': ['C'], 'Co': ['C'], 'Cn': ['C'],
+}
+
+# these are the surrogate codepoints, which are not valid rust characters
+surrogate_codepoints = (0xd800, 0xdfff)
+
+def fetch(f):
+ if not os.path.exists(os.path.basename(f)):
+ os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s"
+ % f)
+
+ if not os.path.exists(os.path.basename(f)):
+ sys.stderr.write("cannot load %s" % f)
+ exit(1)
+
+def is_surrogate(n):
+ return surrogate_codepoints[0] <= n <= surrogate_codepoints[1]
+
+def load_unicode_data(f):
+ fetch(f)
+ gencats = {}
+
+ udict = {}
+ range_start = -1
+ for line in fileinput.input(f):
+ data = line.split(';')
+ if len(data) != 15:
+ continue
+ cp = int(data[0], 16)
+ if is_surrogate(cp):
+ continue
+ if range_start >= 0:
+ for i in range(range_start, cp):
+ udict[i] = data
+ range_start = -1
+ if data[1].endswith(", First>"):
+ range_start = cp
+ continue
+ udict[cp] = data
+
+ for code in udict:
+ [code_org, name, gencat, combine, bidi,
+ decomp, deci, digit, num, mirror,
+ old, iso, upcase, lowcase, titlecase ] = udict[code]
+
+ # place letter in categories as appropriate
+ for cat in [gencat, "Assigned"] + expanded_categories.get(gencat, []):
+ if cat not in gencats:
+ gencats[cat] = []
+ gencats[cat].append(code)
+
+ gencats = group_cats(gencats)
+
+ return gencats
+
+def group_cats(cats):
+ cats_out = {}
+ for cat in cats:
+ cats_out[cat] = group_cat(cats[cat])
+ return cats_out
+
+def group_cat(cat):
+ cat_out = []
+ letters = sorted(set(cat))
+ cur_start = letters.pop(0)
+ cur_end = cur_start
+ for letter in letters:
+ assert letter > cur_end, \
+ "cur_end: %s, letter: %s" % (hex(cur_end), hex(letter))
+ if letter == cur_end + 1:
+ cur_end = letter
+ else:
+ cat_out.append((cur_start, cur_end))
+ cur_start = cur_end = letter
+ cat_out.append((cur_start, cur_end))
+ return cat_out
+
+def format_table_content(f, content, indent):
+ line = " "*indent
+ first = True
+ for chunk in content.split(","):
+ if len(line) + len(chunk) < 98:
+ if first:
+ line += chunk
+ else:
+ line += ", " + chunk
+ first = False
+ else:
+ f.write(line + ",\n")
+ line = " "*indent + chunk
+ f.write(line)
+
+# load all widths of want_widths, except those in except_cats
+def load_east_asian_width(want_widths, except_cats):
+ f = "EastAsianWidth.txt"
+ fetch(f)
+ widths = {}
+ re1 = re.compile("^([0-9A-F]+);(\w+) +# (\w+)")
+ re2 = re.compile("^([0-9A-F]+)\.\.([0-9A-F]+);(\w+) +# (\w+)")
+
+ for line in fileinput.input(f):
+ width = None
+ d_lo = 0
+ d_hi = 0
+ cat = None
+ m = re1.match(line)
+ if m:
+ d_lo = m.group(1)
+ d_hi = m.group(1)
+ width = m.group(2)
+ cat = m.group(3)
+ else:
+ m = re2.match(line)
+ if m:
+ d_lo = m.group(1)
+ d_hi = m.group(2)
+ width = m.group(3)
+ cat = m.group(4)
+ else:
+ continue
+ if cat in except_cats or width not in want_widths:
+ continue
+ d_lo = int(d_lo, 16)
+ d_hi = int(d_hi, 16)
+ if width not in widths:
+ widths[width] = []
+ widths[width].append((d_lo, d_hi))
+ return widths
+
+def escape_char(c):
+ return "'\\u{%x}'" % c
+
+def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True,
+ pfun=lambda x: "(%s,%s)" % (escape_char(x[0]), escape_char(x[1])), is_const=True):
+ pub_string = "const"
+ if not is_const:
+ pub_string = "let"
+ if is_pub:
+ pub_string = "pub " + pub_string
+ f.write(" %s %s: %s = &[\n" % (pub_string, name, t_type))
+ data = ""
+ first = True
+ for dat in t_data:
+ if not first:
+ data += ","
+ first = False
+ data += pfun(dat)
+ format_table_content(f, data, 8)
+ f.write("\n ];\n\n")
+
+def emit_charwidth_module(f, width_table):
+ f.write("pub mod charwidth {")
+ f.write("""
+ use core::option::Option::{self, Some, None};
+ use core::result::Result::{Ok, Err};
+
+ #[inline]
+ fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ match r.binary_search_by(|&(lo, hi, _, _)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }) {
+ Ok(idx) => {
+ let (_, _, r_ncjk, r_cjk) = r[idx];
+ if is_cjk { r_cjk } else { r_ncjk }
+ }
+ Err(_) => 1
+ }
+ }
+""")
+
+ f.write("""
+ #[inline]
+ pub fn width(c: char, is_cjk: bool) -> Option<usize> {
+ match c as usize {
+ _c @ 0 => Some(0), // null is zero width
+ cu if cu < 0x20 => None, // control sequences have no width
+ cu if cu < 0x7F => Some(1), // ASCII
+ cu if cu < 0xA0 => None, // more control sequences
+ _ => Some(bsearch_range_value_table(c, is_cjk, charwidth_table) as usize)
+ }
+ }
+
+""")
+
+ f.write(" // character width table. Based on Markus Kuhn's free wcwidth() implementation,\n")
+ f.write(" // http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c\n")
+ emit_table(f, "charwidth_table", width_table, "&'static [(char, char, u8, u8)]", is_pub=False,
+ pfun=lambda x: "(%s,%s,%s,%s)" % (escape_char(x[0]), escape_char(x[1]), x[2], x[3]))
+ f.write("}\n\n")
+
+def remove_from_wtable(wtable, val):
+ wtable_out = []
+ while wtable:
+ if wtable[0][1] < val:
+ wtable_out.append(wtable.pop(0))
+ elif wtable[0][0] > val:
+ break
+ else:
+ (wt_lo, wt_hi, width, width_cjk) = wtable.pop(0)
+ if wt_lo == wt_hi == val:
+ continue
+ elif wt_lo == val:
+ wtable_out.append((wt_lo+1, wt_hi, width, width_cjk))
+ elif wt_hi == val:
+ wtable_out.append((wt_lo, wt_hi-1, width, width_cjk))
+ else:
+ wtable_out.append((wt_lo, val-1, width, width_cjk))
+ wtable_out.append((val+1, wt_hi, width, width_cjk))
+ if wtable:
+ wtable_out.extend(wtable)
+ return wtable_out
+
+
+
+def optimize_width_table(wtable):
+ wtable_out = []
+ w_this = wtable.pop(0)
+ while wtable:
+ if w_this[1] == wtable[0][0] - 1 and w_this[2:3] == wtable[0][2:3]:
+ w_tmp = wtable.pop(0)
+ w_this = (w_this[0], w_tmp[1], w_tmp[2], w_tmp[3])
+ else:
+ wtable_out.append(w_this)
+ w_this = wtable.pop(0)
+ wtable_out.append(w_this)
+ return wtable_out
+
+if __name__ == "__main__":
+ r = "tables.rs"
+ if os.path.exists(r):
+ os.remove(r)
+ with open(r, "w") as rf:
+ # write the file's preamble
+ rf.write(preamble)
+
+ # download and parse all the data
+ fetch("ReadMe.txt")
+ with open("ReadMe.txt") as readme:
+ pattern = "for Version (\d+)\.(\d+)\.(\d+) of the Unicode"
+ unicode_version = re.search(pattern, readme.read()).groups()
+ rf.write("""
+/// The version of [Unicode](http://www.unicode.org/)
+/// that this version of unicode-width is based on.
+pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
+
+""" % unicode_version)
+ gencats = load_unicode_data("UnicodeData.txt")
+
+ ### character width module
+ width_table = []
+ for zwcat in ["Me", "Mn", "Cf"]:
+ width_table.extend([(lo_hi[0], lo_hi[1], 0, 0) for lo_hi in gencats[zwcat]])
+ width_table.append((4448, 4607, 0, 0))
+
+ # get widths, except those that are explicitly marked zero-width above
+ ea_widths = load_east_asian_width(["W", "F", "A"], ["Me", "Mn", "Cf"])
+ # these are doublewidth
+ for dwcat in ["W", "F"]:
+ width_table.extend([(lo_hi1[0], lo_hi1[1], 2, 2) for lo_hi1 in ea_widths[dwcat]])
+ width_table.extend([(lo_hi2[0], lo_hi2[1], 1, 2) for lo_hi2 in ea_widths["A"]])
+
+ width_table.sort(key=lambda w: w[0])
+
+ # soft hyphen is not zero width in preformatted text; it's used to indicate
+ # a hyphen inserted to facilitate a linebreak.
+ width_table = remove_from_wtable(width_table, 173)
+
+ # optimize the width table by collapsing adjacent entities when possible
+ width_table = optimize_width_table(width_table)
+ emit_charwidth_module(rf, width_table)
diff --git a/unicode-width/src/lib.rs b/unicode-width/src/lib.rs
new file mode 100644
index 0000000..1ee35c8
--- /dev/null
+++ b/unicode-width/src/lib.rs
@@ -0,0 +1,131 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Determine displayed width of `char` and `str` types according to
+//! [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
+//! rules.
+//!
+//! ```rust
+//! extern crate unicode_width;
+//!
+//! use unicode_width::UnicodeWidthStr;
+//!
+//! fn main() {
+//! let teststr = "Hello, world!";
+//! let width = UnicodeWidthStr::width(teststr);
+//! println!("{}", teststr);
+//! println!("The above string is {} columns wide.", width);
+//! let width = teststr.width_cjk();
+//! println!("The above string is {} columns wide (CJK).", width);
+//! }
+//! ```
+//!
+//! # features
+//!
+//! unicode-width supports a `no_std` feature. This eliminates dependence
+//! on std, and instead uses equivalent functions from core.
+//!
+//! # crates.io
+//!
+//! You can use this package in your project by adding the following
+//! to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! unicode-width = "0.1.5"
+//! ```
+
+#![deny(missing_docs, unsafe_code)]
+#![doc(html_logo_url = "https://unicode-rs.github.io/unicode-rs_sm.png",
+ html_favicon_url = "https://unicode-rs.github.io/unicode-rs_sm.png")]
+
+#![cfg_attr(feature = "bench", feature(test))]
+#![no_std]
+
+#[cfg(test)]
+#[macro_use]
+extern crate std;
+
+#[cfg(feature = "bench")]
+extern crate test;
+
+use tables::charwidth as cw;
+pub use tables::UNICODE_VERSION;
+
+use core::ops::Add;
+
+mod tables;
+
+#[cfg(test)]
+mod tests;
+
+/// Methods for determining displayed width of Unicode characters.
+pub trait UnicodeWidthChar {
+ /// Returns the character's displayed width in columns, or `None` if the
+ /// character is a control character other than `'\x00'`.
+ ///
+ /// This function treats characters in the Ambiguous category according
+ /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
+ /// as 1 column wide. This is consistent with the recommendations for non-CJK
+ /// contexts, or when the context cannot be reliably determined.
+ fn width(self) -> Option<usize>;
+
+ /// Returns the character's displayed width in columns, or `None` if the
+ /// character is a control character other than `'\x00'`.
+ ///
+ /// This function treats characters in the Ambiguous category according
+ /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
+ /// as 2 columns wide. This is consistent with the recommendations for
+ /// CJK contexts.
+ fn width_cjk(self) -> Option<usize>;
+}
+
+impl UnicodeWidthChar for char {
+ #[inline]
+ fn width(self) -> Option<usize> { cw::width(self, false) }
+
+ #[inline]
+ fn width_cjk(self) -> Option<usize> { cw::width(self, true) }
+}
+
+/// Methods for determining displayed width of Unicode strings.
+pub trait UnicodeWidthStr {
+ /// Returns the string's displayed width in columns.
+ ///
+ /// Control characters are treated as having zero width.
+ ///
+ /// This function treats characters in the Ambiguous category according
+ /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
+ /// as 1 column wide. This is consistent with the recommendations for
+ /// non-CJK contexts, or when the context cannot be reliably determined.
+ fn width<'a>(&'a self) -> usize;
+
+ /// Returns the string's displayed width in columns.
+ ///
+ /// Control characters are treated as having zero width.
+ ///
+ /// This function treats characters in the Ambiguous category according
+ /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
+ /// as 2 column wide. This is consistent with the recommendations for
+ /// CJK contexts.
+ fn width_cjk<'a>(&'a self) -> usize;
+}
+
+impl UnicodeWidthStr for str {
+ #[inline]
+ fn width(&self) -> usize {
+ self.chars().map(|c| cw::width(c, false).unwrap_or(0)).fold(0, Add::add)
+ }
+
+ #[inline]
+ fn width_cjk(&self) -> usize {
+ self.chars().map(|c| cw::width(c, true).unwrap_or(0)).fold(0, Add::add)
+ }
+}
diff --git a/unicode-width/src/tables.rs b/unicode-width/src/tables.rs
new file mode 100644
index 0000000..7ae450b
--- /dev/null
+++ b/unicode-width/src/tables.rs
@@ -0,0 +1,284 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly
+
+#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
+
+/// The version of [Unicode](http://www.unicode.org/)
+/// that this version of unicode-width is based on.
+pub const UNICODE_VERSION: (u64, u64, u64) = (12, 1, 0);
+
+pub mod charwidth {
+ use core::option::Option::{self, Some, None};
+ use core::result::Result::{Ok, Err};
+
+ #[inline]
+ fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+ match r.binary_search_by(|&(lo, hi, _, _)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }) {
+ Ok(idx) => {
+ let (_, _, r_ncjk, r_cjk) = r[idx];
+ if is_cjk { r_cjk } else { r_ncjk }
+ }
+ Err(_) => 1
+ }
+ }
+
+ #[inline]
+ pub fn width(c: char, is_cjk: bool) -> Option<usize> {
+ match c as usize {
+ _c @ 0 => Some(0), // null is zero width
+ cu if cu < 0x20 => None, // control sequences have no width
+ cu if cu < 0x7F => Some(1), // ASCII
+ cu if cu < 0xA0 => None, // more control sequences
+ _ => Some(bsearch_range_value_table(c, is_cjk, charwidth_table) as usize)
+ }
+ }
+
+ // character width table. Based on Markus Kuhn's free wcwidth() implementation,
+ // http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ const charwidth_table: &'static [(char, char, u8, u8)] = &[
+ ('\u{a1}', '\u{a1}', 1, 2), ('\u{a4}', '\u{a4}', 1, 2), ('\u{a7}', '\u{a8}', 1, 2),
+ ('\u{aa}', '\u{aa}', 1, 2), ('\u{ae}', '\u{ae}', 1, 2), ('\u{b0}', '\u{b4}', 1, 2),
+ ('\u{b6}', '\u{ba}', 1, 2), ('\u{bc}', '\u{bf}', 1, 2), ('\u{c6}', '\u{c6}', 1, 2),
+ ('\u{d0}', '\u{d0}', 1, 2), ('\u{d7}', '\u{d8}', 1, 2), ('\u{de}', '\u{e1}', 1, 2),
+ ('\u{e6}', '\u{e6}', 1, 2), ('\u{e8}', '\u{ea}', 1, 2), ('\u{ec}', '\u{ed}', 1, 2),
+ ('\u{f0}', '\u{f0}', 1, 2), ('\u{f2}', '\u{f3}', 1, 2), ('\u{f7}', '\u{fa}', 1, 2),
+ ('\u{fc}', '\u{fc}', 1, 2), ('\u{fe}', '\u{fe}', 1, 2), ('\u{101}', '\u{101}', 1, 2),
+ ('\u{111}', '\u{111}', 1, 2), ('\u{113}', '\u{113}', 1, 2), ('\u{11b}', '\u{11b}', 1, 2),
+ ('\u{126}', '\u{127}', 1, 2), ('\u{12b}', '\u{12b}', 1, 2), ('\u{131}', '\u{133}', 1, 2),
+ ('\u{138}', '\u{138}', 1, 2), ('\u{13f}', '\u{142}', 1, 2), ('\u{144}', '\u{144}', 1, 2),
+ ('\u{148}', '\u{14b}', 1, 2), ('\u{14d}', '\u{14d}', 1, 2), ('\u{152}', '\u{153}', 1, 2),
+ ('\u{166}', '\u{167}', 1, 2), ('\u{16b}', '\u{16b}', 1, 2), ('\u{1ce}', '\u{1ce}', 1, 2),
+ ('\u{1d0}', '\u{1d0}', 1, 2), ('\u{1d2}', '\u{1d2}', 1, 2), ('\u{1d4}', '\u{1d4}', 1, 2),
+ ('\u{1d6}', '\u{1d6}', 1, 2), ('\u{1d8}', '\u{1d8}', 1, 2), ('\u{1da}', '\u{1da}', 1, 2),
+ ('\u{1dc}', '\u{1dc}', 1, 2), ('\u{251}', '\u{251}', 1, 2), ('\u{261}', '\u{261}', 1, 2),
+ ('\u{2c4}', '\u{2c4}', 1, 2), ('\u{2c7}', '\u{2c7}', 1, 2), ('\u{2c9}', '\u{2cb}', 1, 2),
+ ('\u{2cd}', '\u{2cd}', 1, 2), ('\u{2d0}', '\u{2d0}', 1, 2), ('\u{2d8}', '\u{2db}', 1, 2),
+ ('\u{2dd}', '\u{2dd}', 1, 2), ('\u{2df}', '\u{2df}', 1, 2), ('\u{300}', '\u{36f}', 0, 0),
+ ('\u{391}', '\u{3a1}', 1, 2), ('\u{3a3}', '\u{3a9}', 1, 2), ('\u{3b1}', '\u{3c1}', 1, 2),
+ ('\u{3c3}', '\u{3c9}', 1, 2), ('\u{401}', '\u{401}', 1, 2), ('\u{410}', '\u{44f}', 1, 2),
+ ('\u{451}', '\u{451}', 1, 2), ('\u{483}', '\u{489}', 0, 0), ('\u{591}', '\u{5bd}', 0, 0),
+ ('\u{5bf}', '\u{5bf}', 0, 0), ('\u{5c1}', '\u{5c2}', 0, 0), ('\u{5c4}', '\u{5c5}', 0, 0),
+ ('\u{5c7}', '\u{5c7}', 0, 0), ('\u{600}', '\u{605}', 0, 0), ('\u{610}', '\u{61a}', 0, 0),
+ ('\u{61c}', '\u{61c}', 0, 0), ('\u{64b}', '\u{65f}', 0, 0), ('\u{670}', '\u{670}', 0, 0),
+ ('\u{6d6}', '\u{6dd}', 0, 0), ('\u{6df}', '\u{6e4}', 0, 0), ('\u{6e7}', '\u{6e8}', 0, 0),
+ ('\u{6ea}', '\u{6ed}', 0, 0), ('\u{70f}', '\u{70f}', 0, 0), ('\u{711}', '\u{711}', 0, 0),
+ ('\u{730}', '\u{74a}', 0, 0), ('\u{7a6}', '\u{7b0}', 0, 0), ('\u{7eb}', '\u{7f3}', 0, 0),
+ ('\u{7fd}', '\u{7fd}', 0, 0), ('\u{816}', '\u{819}', 0, 0), ('\u{81b}', '\u{823}', 0, 0),
+ ('\u{825}', '\u{827}', 0, 0), ('\u{829}', '\u{82d}', 0, 0), ('\u{859}', '\u{85b}', 0, 0),
+ ('\u{8d3}', '\u{902}', 0, 0), ('\u{93a}', '\u{93a}', 0, 0), ('\u{93c}', '\u{93c}', 0, 0),
+ ('\u{941}', '\u{948}', 0, 0), ('\u{94d}', '\u{94d}', 0, 0), ('\u{951}', '\u{957}', 0, 0),
+ ('\u{962}', '\u{963}', 0, 0), ('\u{981}', '\u{981}', 0, 0), ('\u{9bc}', '\u{9bc}', 0, 0),
+ ('\u{9c1}', '\u{9c4}', 0, 0), ('\u{9cd}', '\u{9cd}', 0, 0), ('\u{9e2}', '\u{9e3}', 0, 0),
+ ('\u{9fe}', '\u{9fe}', 0, 0), ('\u{a01}', '\u{a02}', 0, 0), ('\u{a3c}', '\u{a3c}', 0, 0),
+ ('\u{a41}', '\u{a42}', 0, 0), ('\u{a47}', '\u{a48}', 0, 0), ('\u{a4b}', '\u{a4d}', 0, 0),
+ ('\u{a51}', '\u{a51}', 0, 0), ('\u{a70}', '\u{a71}', 0, 0), ('\u{a75}', '\u{a75}', 0, 0),
+ ('\u{a81}', '\u{a82}', 0, 0), ('\u{abc}', '\u{abc}', 0, 0), ('\u{ac1}', '\u{ac5}', 0, 0),
+ ('\u{ac7}', '\u{ac8}', 0, 0), ('\u{acd}', '\u{acd}', 0, 0), ('\u{ae2}', '\u{ae3}', 0, 0),
+ ('\u{afa}', '\u{aff}', 0, 0), ('\u{b01}', '\u{b01}', 0, 0), ('\u{b3c}', '\u{b3c}', 0, 0),
+ ('\u{b3f}', '\u{b3f}', 0, 0), ('\u{b41}', '\u{b44}', 0, 0), ('\u{b4d}', '\u{b4d}', 0, 0),
+ ('\u{b56}', '\u{b56}', 0, 0), ('\u{b62}', '\u{b63}', 0, 0), ('\u{b82}', '\u{b82}', 0, 0),
+ ('\u{bc0}', '\u{bc0}', 0, 0), ('\u{bcd}', '\u{bcd}', 0, 0), ('\u{c00}', '\u{c00}', 0, 0),
+ ('\u{c04}', '\u{c04}', 0, 0), ('\u{c3e}', '\u{c40}', 0, 0), ('\u{c46}', '\u{c48}', 0, 0),
+ ('\u{c4a}', '\u{c4d}', 0, 0), ('\u{c55}', '\u{c56}', 0, 0), ('\u{c62}', '\u{c63}', 0, 0),
+ ('\u{c81}', '\u{c81}', 0, 0), ('\u{cbc}', '\u{cbc}', 0, 0), ('\u{cbf}', '\u{cbf}', 0, 0),
+ ('\u{cc6}', '\u{cc6}', 0, 0), ('\u{ccc}', '\u{ccd}', 0, 0), ('\u{ce2}', '\u{ce3}', 0, 0),
+ ('\u{d00}', '\u{d01}', 0, 0), ('\u{d3b}', '\u{d3c}', 0, 0), ('\u{d41}', '\u{d44}', 0, 0),
+ ('\u{d4d}', '\u{d4d}', 0, 0), ('\u{d62}', '\u{d63}', 0, 0), ('\u{dca}', '\u{dca}', 0, 0),
+ ('\u{dd2}', '\u{dd4}', 0, 0), ('\u{dd6}', '\u{dd6}', 0, 0), ('\u{e31}', '\u{e31}', 0, 0),
+ ('\u{e34}', '\u{e3a}', 0, 0), ('\u{e47}', '\u{e4e}', 0, 0), ('\u{eb1}', '\u{eb1}', 0, 0),
+ ('\u{eb4}', '\u{ebc}', 0, 0), ('\u{ec8}', '\u{ecd}', 0, 0), ('\u{f18}', '\u{f19}', 0, 0),
+ ('\u{f35}', '\u{f35}', 0, 0), ('\u{f37}', '\u{f37}', 0, 0), ('\u{f39}', '\u{f39}', 0, 0),
+ ('\u{f71}', '\u{f7e}', 0, 0), ('\u{f80}', '\u{f84}', 0, 0), ('\u{f86}', '\u{f87}', 0, 0),
+ ('\u{f8d}', '\u{f97}', 0, 0), ('\u{f99}', '\u{fbc}', 0, 0), ('\u{fc6}', '\u{fc6}', 0, 0),
+ ('\u{102d}', '\u{1030}', 0, 0), ('\u{1032}', '\u{1037}', 0, 0), ('\u{1039}', '\u{103a}', 0,
+ 0), ('\u{103d}', '\u{103e}', 0, 0), ('\u{1058}', '\u{1059}', 0, 0), ('\u{105e}', '\u{1060}',
+ 0, 0), ('\u{1071}', '\u{1074}', 0, 0), ('\u{1082}', '\u{1082}', 0, 0), ('\u{1085}',
+ '\u{1086}', 0, 0), ('\u{108d}', '\u{108d}', 0, 0), ('\u{109d}', '\u{109d}', 0, 0),
+ ('\u{1100}', '\u{115f}', 2, 2), ('\u{1160}', '\u{11ff}', 0, 0), ('\u{135d}', '\u{135f}', 0,
+ 0), ('\u{1712}', '\u{1714}', 0, 0), ('\u{1732}', '\u{1734}', 0, 0), ('\u{1752}', '\u{1753}',
+ 0, 0), ('\u{1772}', '\u{1773}', 0, 0), ('\u{17b4}', '\u{17b5}', 0, 0), ('\u{17b7}',
+ '\u{17bd}', 0, 0), ('\u{17c6}', '\u{17c6}', 0, 0), ('\u{17c9}', '\u{17d3}', 0, 0),
+ ('\u{17dd}', '\u{17dd}', 0, 0), ('\u{180b}', '\u{180e}', 0, 0), ('\u{1885}', '\u{1886}', 0,
+ 0), ('\u{18a9}', '\u{18a9}', 0, 0), ('\u{1920}', '\u{1922}', 0, 0), ('\u{1927}', '\u{1928}',
+ 0, 0), ('\u{1932}', '\u{1932}', 0, 0), ('\u{1939}', '\u{193b}', 0, 0), ('\u{1a17}',
+ '\u{1a18}', 0, 0), ('\u{1a1b}', '\u{1a1b}', 0, 0), ('\u{1a56}', '\u{1a56}', 0, 0),
+ ('\u{1a58}', '\u{1a5e}', 0, 0), ('\u{1a60}', '\u{1a60}', 0, 0), ('\u{1a62}', '\u{1a62}', 0,
+ 0), ('\u{1a65}', '\u{1a6c}', 0, 0), ('\u{1a73}', '\u{1a7c}', 0, 0), ('\u{1a7f}', '\u{1a7f}',
+ 0, 0), ('\u{1ab0}', '\u{1abe}', 0, 0), ('\u{1b00}', '\u{1b03}', 0, 0), ('\u{1b34}',
+ '\u{1b34}', 0, 0), ('\u{1b36}', '\u{1b3a}', 0, 0), ('\u{1b3c}', '\u{1b3c}', 0, 0),
+ ('\u{1b42}', '\u{1b42}', 0, 0), ('\u{1b6b}', '\u{1b73}', 0, 0), ('\u{1b80}', '\u{1b81}', 0,
+ 0), ('\u{1ba2}', '\u{1ba5}', 0, 0), ('\u{1ba8}', '\u{1ba9}', 0, 0), ('\u{1bab}', '\u{1bad}',
+ 0, 0), ('\u{1be6}', '\u{1be6}', 0, 0), ('\u{1be8}', '\u{1be9}', 0, 0), ('\u{1bed}',
+ '\u{1bed}', 0, 0), ('\u{1bef}', '\u{1bf1}', 0, 0), ('\u{1c2c}', '\u{1c33}', 0, 0),
+ ('\u{1c36}', '\u{1c37}', 0, 0), ('\u{1cd0}', '\u{1cd2}', 0, 0), ('\u{1cd4}', '\u{1ce0}', 0,
+ 0), ('\u{1ce2}', '\u{1ce8}', 0, 0), ('\u{1ced}', '\u{1ced}', 0, 0), ('\u{1cf4}', '\u{1cf4}',
+ 0, 0), ('\u{1cf8}', '\u{1cf9}', 0, 0), ('\u{1dc0}', '\u{1df9}', 0, 0), ('\u{1dfb}',
+ '\u{1dff}', 0, 0), ('\u{200b}', '\u{200f}', 0, 0), ('\u{2010}', '\u{2010}', 1, 2),
+ ('\u{2013}', '\u{2016}', 1, 2), ('\u{2018}', '\u{2019}', 1, 2), ('\u{201c}', '\u{201d}', 1,
+ 2), ('\u{2020}', '\u{2022}', 1, 2), ('\u{2024}', '\u{2027}', 1, 2), ('\u{202a}', '\u{202e}',
+ 0, 0), ('\u{2030}', '\u{2030}', 1, 2), ('\u{2032}', '\u{2033}', 1, 2), ('\u{2035}',
+ '\u{2035}', 1, 2), ('\u{203b}', '\u{203b}', 1, 2), ('\u{203e}', '\u{203e}', 1, 2),
+ ('\u{2060}', '\u{2064}', 0, 0), ('\u{2066}', '\u{206f}', 0, 0), ('\u{2074}', '\u{2074}', 1,
+ 2), ('\u{207f}', '\u{207f}', 1, 2), ('\u{2081}', '\u{2084}', 1, 2), ('\u{20ac}', '\u{20ac}',
+ 1, 2), ('\u{20d0}', '\u{20f0}', 0, 0), ('\u{2103}', '\u{2103}', 1, 2), ('\u{2105}',
+ '\u{2105}', 1, 2), ('\u{2109}', '\u{2109}', 1, 2), ('\u{2113}', '\u{2113}', 1, 2),
+ ('\u{2116}', '\u{2116}', 1, 2), ('\u{2121}', '\u{2122}', 1, 2), ('\u{2126}', '\u{2126}', 1,
+ 2), ('\u{212b}', '\u{212b}', 1, 2), ('\u{2153}', '\u{2154}', 1, 2), ('\u{215b}', '\u{215e}',
+ 1, 2), ('\u{2160}', '\u{216b}', 1, 2), ('\u{2170}', '\u{2179}', 1, 2), ('\u{2189}',
+ '\u{2189}', 1, 2), ('\u{2190}', '\u{2199}', 1, 2), ('\u{21b8}', '\u{21b9}', 1, 2),
+ ('\u{21d2}', '\u{21d2}', 1, 2), ('\u{21d4}', '\u{21d4}', 1, 2), ('\u{21e7}', '\u{21e7}', 1,
+ 2), ('\u{2200}', '\u{2200}', 1, 2), ('\u{2202}', '\u{2203}', 1, 2), ('\u{2207}', '\u{2208}',
+ 1, 2), ('\u{220b}', '\u{220b}', 1, 2), ('\u{220f}', '\u{220f}', 1, 2), ('\u{2211}',
+ '\u{2211}', 1, 2), ('\u{2215}', '\u{2215}', 1, 2), ('\u{221a}', '\u{221a}', 1, 2),
+ ('\u{221d}', '\u{2220}', 1, 2), ('\u{2223}', '\u{2223}', 1, 2), ('\u{2225}', '\u{2225}', 1,
+ 2), ('\u{2227}', '\u{222c}', 1, 2), ('\u{222e}', '\u{222e}', 1, 2), ('\u{2234}', '\u{2237}',
+ 1, 2), ('\u{223c}', '\u{223d}', 1, 2), ('\u{2248}', '\u{2248}', 1, 2), ('\u{224c}',
+ '\u{224c}', 1, 2), ('\u{2252}', '\u{2252}', 1, 2), ('\u{2260}', '\u{2261}', 1, 2),
+ ('\u{2264}', '\u{2267}', 1, 2), ('\u{226a}', '\u{226b}', 1, 2), ('\u{226e}', '\u{226f}', 1,
+ 2), ('\u{2282}', '\u{2283}', 1, 2), ('\u{2286}', '\u{2287}', 1, 2), ('\u{2295}', '\u{2295}',
+ 1, 2), ('\u{2299}', '\u{2299}', 1, 2), ('\u{22a5}', '\u{22a5}', 1, 2), ('\u{22bf}',
+ '\u{22bf}', 1, 2), ('\u{2312}', '\u{2312}', 1, 2), ('\u{231a}', '\u{231b}', 2, 2),
+ ('\u{2329}', '\u{232a}', 2, 2), ('\u{23e9}', '\u{23ec}', 2, 2), ('\u{23f0}', '\u{23f0}', 2,
+ 2), ('\u{23f3}', '\u{23f3}', 2, 2), ('\u{2460}', '\u{24e9}', 1, 2), ('\u{24eb}', '\u{254b}',
+ 1, 2), ('\u{2550}', '\u{2573}', 1, 2), ('\u{2580}', '\u{258f}', 1, 2), ('\u{2592}',
+ '\u{2595}', 1, 2), ('\u{25a0}', '\u{25a1}', 1, 2), ('\u{25a3}', '\u{25a9}', 1, 2),
+ ('\u{25b2}', '\u{25b3}', 1, 2), ('\u{25b6}', '\u{25b7}', 1, 2), ('\u{25bc}', '\u{25bd}', 1,
+ 2), ('\u{25c0}', '\u{25c1}', 1, 2), ('\u{25c6}', '\u{25c8}', 1, 2), ('\u{25cb}', '\u{25cb}',
+ 1, 2), ('\u{25ce}', '\u{25d1}', 1, 2), ('\u{25e2}', '\u{25e5}', 1, 2), ('\u{25ef}',
+ '\u{25ef}', 1, 2), ('\u{25fd}', '\u{25fe}', 2, 2), ('\u{2605}', '\u{2606}', 1, 2),
+ ('\u{2609}', '\u{2609}', 1, 2), ('\u{260e}', '\u{260f}', 1, 2), ('\u{2614}', '\u{2615}', 2,
+ 2), ('\u{261c}', '\u{261c}', 1, 2), ('\u{261e}', '\u{261e}', 1, 2), ('\u{2640}', '\u{2640}',
+ 1, 2), ('\u{2642}', '\u{2642}', 1, 2), ('\u{2648}', '\u{2653}', 2, 2), ('\u{2660}',
+ '\u{2661}', 1, 2), ('\u{2663}', '\u{2665}', 1, 2), ('\u{2667}', '\u{266a}', 1, 2),
+ ('\u{266c}', '\u{266d}', 1, 2), ('\u{266f}', '\u{266f}', 1, 2), ('\u{267f}', '\u{267f}', 2,
+ 2), ('\u{2693}', '\u{2693}', 2, 2), ('\u{269e}', '\u{269f}', 1, 2), ('\u{26a1}', '\u{26a1}',
+ 2, 2), ('\u{26aa}', '\u{26ab}', 2, 2), ('\u{26bd}', '\u{26be}', 2, 2), ('\u{26bf}',
+ '\u{26bf}', 1, 2), ('\u{26c4}', '\u{26c5}', 2, 2), ('\u{26c6}', '\u{26cd}', 1, 2),
+ ('\u{26ce}', '\u{26ce}', 2, 2), ('\u{26cf}', '\u{26d3}', 1, 2), ('\u{26d4}', '\u{26d4}', 2,
+ 2), ('\u{26d5}', '\u{26e1}', 1, 2), ('\u{26e3}', '\u{26e3}', 1, 2), ('\u{26e8}', '\u{26e9}',
+ 1, 2), ('\u{26ea}', '\u{26ea}', 2, 2), ('\u{26eb}', '\u{26f1}', 1, 2), ('\u{26f2}',
+ '\u{26f3}', 2, 2), ('\u{26f4}', '\u{26f4}', 1, 2), ('\u{26f5}', '\u{26f5}', 2, 2),
+ ('\u{26f6}', '\u{26f9}', 1, 2), ('\u{26fa}', '\u{26fa}', 2, 2), ('\u{26fb}', '\u{26fc}', 1,
+ 2), ('\u{26fd}', '\u{26fd}', 2, 2), ('\u{26fe}', '\u{26ff}', 1, 2), ('\u{2705}', '\u{2705}',
+ 2, 2), ('\u{270a}', '\u{270b}', 2, 2), ('\u{2728}', '\u{2728}', 2, 2), ('\u{273d}',
+ '\u{273d}', 1, 2), ('\u{274c}', '\u{274c}', 2, 2), ('\u{274e}', '\u{274e}', 2, 2),
+ ('\u{2753}', '\u{2755}', 2, 2), ('\u{2757}', '\u{2757}', 2, 2), ('\u{2776}', '\u{277f}', 1,
+ 2), ('\u{2795}', '\u{2797}', 2, 2), ('\u{27b0}', '\u{27b0}', 2, 2), ('\u{27bf}', '\u{27bf}',
+ 2, 2), ('\u{2b1b}', '\u{2b1c}', 2, 2), ('\u{2b50}', '\u{2b50}', 2, 2), ('\u{2b55}',
+ '\u{2b55}', 2, 2), ('\u{2b56}', '\u{2b59}', 1, 2), ('\u{2cef}', '\u{2cf1}', 0, 0),
+ ('\u{2d7f}', '\u{2d7f}', 0, 0), ('\u{2de0}', '\u{2dff}', 0, 0), ('\u{2e80}', '\u{2e99}', 2,
+ 2), ('\u{2e9b}', '\u{2ef3}', 2, 2), ('\u{2f00}', '\u{2fd5}', 2, 2), ('\u{2ff0}', '\u{2ffb}',
+ 2, 2), ('\u{3000}', '\u{3029}', 2, 2), ('\u{302a}', '\u{302d}', 0, 0), ('\u{302e}',
+ '\u{303e}', 2, 2), ('\u{3041}', '\u{3096}', 2, 2), ('\u{3099}', '\u{309a}', 0, 0),
+ ('\u{309b}', '\u{30ff}', 2, 2), ('\u{3105}', '\u{312f}', 2, 2), ('\u{3131}', '\u{318e}', 2,
+ 2), ('\u{3190}', '\u{31ba}', 2, 2), ('\u{31c0}', '\u{31e3}', 2, 2), ('\u{31f0}', '\u{321e}',
+ 2, 2), ('\u{3220}', '\u{3247}', 2, 2), ('\u{3248}', '\u{324f}', 1, 2), ('\u{3250}',
+ '\u{4dbf}', 2, 2), ('\u{4e00}', '\u{a48c}', 2, 2), ('\u{a490}', '\u{a4c6}', 2, 2),
+ ('\u{a66f}', '\u{a672}', 0, 0), ('\u{a674}', '\u{a67d}', 0, 0), ('\u{a69e}', '\u{a69f}', 0,
+ 0), ('\u{a6f0}', '\u{a6f1}', 0, 0), ('\u{a802}', '\u{a802}', 0, 0), ('\u{a806}', '\u{a806}',
+ 0, 0), ('\u{a80b}', '\u{a80b}', 0, 0), ('\u{a825}', '\u{a826}', 0, 0), ('\u{a8c4}',
+ '\u{a8c5}', 0, 0), ('\u{a8e0}', '\u{a8f1}', 0, 0), ('\u{a8ff}', '\u{a8ff}', 0, 0),
+ ('\u{a926}', '\u{a92d}', 0, 0), ('\u{a947}', '\u{a951}', 0, 0), ('\u{a960}', '\u{a97c}', 2,
+ 2), ('\u{a980}', '\u{a982}', 0, 0), ('\u{a9b3}', '\u{a9b3}', 0, 0), ('\u{a9b6}', '\u{a9b9}',
+ 0, 0), ('\u{a9bc}', '\u{a9bd}', 0, 0), ('\u{a9e5}', '\u{a9e5}', 0, 0), ('\u{aa29}',
+ '\u{aa2e}', 0, 0), ('\u{aa31}', '\u{aa32}', 0, 0), ('\u{aa35}', '\u{aa36}', 0, 0),
+ ('\u{aa43}', '\u{aa43}', 0, 0), ('\u{aa4c}', '\u{aa4c}', 0, 0), ('\u{aa7c}', '\u{aa7c}', 0,
+ 0), ('\u{aab0}', '\u{aab0}', 0, 0), ('\u{aab2}', '\u{aab4}', 0, 0), ('\u{aab7}', '\u{aab8}',
+ 0, 0), ('\u{aabe}', '\u{aabf}', 0, 0), ('\u{aac1}', '\u{aac1}', 0, 0), ('\u{aaec}',
+ '\u{aaed}', 0, 0), ('\u{aaf6}', '\u{aaf6}', 0, 0), ('\u{abe5}', '\u{abe5}', 0, 0),
+ ('\u{abe8}', '\u{abe8}', 0, 0), ('\u{abed}', '\u{abed}', 0, 0), ('\u{ac00}', '\u{d7a3}', 2,
+ 2), ('\u{e000}', '\u{f8ff}', 1, 2), ('\u{f900}', '\u{faff}', 2, 2), ('\u{fb1e}', '\u{fb1e}',
+ 0, 0), ('\u{fe00}', '\u{fe0f}', 0, 0), ('\u{fe10}', '\u{fe19}', 2, 2), ('\u{fe20}',
+ '\u{fe2f}', 0, 0), ('\u{fe30}', '\u{fe52}', 2, 2), ('\u{fe54}', '\u{fe66}', 2, 2),
+ ('\u{fe68}', '\u{fe6b}', 2, 2), ('\u{feff}', '\u{feff}', 0, 0), ('\u{ff01}', '\u{ff60}', 2,
+ 2), ('\u{ffe0}', '\u{ffe6}', 2, 2), ('\u{fff9}', '\u{fffb}', 0, 0), ('\u{fffd}', '\u{fffd}',
+ 1, 2), ('\u{101fd}', '\u{101fd}', 0, 0), ('\u{102e0}', '\u{102e0}', 0, 0), ('\u{10376}',
+ '\u{1037a}', 0, 0), ('\u{10a01}', '\u{10a03}', 0, 0), ('\u{10a05}', '\u{10a06}', 0, 0),
+ ('\u{10a0c}', '\u{10a0f}', 0, 0), ('\u{10a38}', '\u{10a3a}', 0, 0), ('\u{10a3f}',
+ '\u{10a3f}', 0, 0), ('\u{10ae5}', '\u{10ae6}', 0, 0), ('\u{10d24}', '\u{10d27}', 0, 0),
+ ('\u{10f46}', '\u{10f50}', 0, 0), ('\u{11001}', '\u{11001}', 0, 0), ('\u{11038}',
+ '\u{11046}', 0, 0), ('\u{1107f}', '\u{11081}', 0, 0), ('\u{110b3}', '\u{110b6}', 0, 0),
+ ('\u{110b9}', '\u{110ba}', 0, 0), ('\u{110bd}', '\u{110bd}', 0, 0), ('\u{110cd}',
+ '\u{110cd}', 0, 0), ('\u{11100}', '\u{11102}', 0, 0), ('\u{11127}', '\u{1112b}', 0, 0),
+ ('\u{1112d}', '\u{11134}', 0, 0), ('\u{11173}', '\u{11173}', 0, 0), ('\u{11180}',
+ '\u{11181}', 0, 0), ('\u{111b6}', '\u{111be}', 0, 0), ('\u{111c9}', '\u{111cc}', 0, 0),
+ ('\u{1122f}', '\u{11231}', 0, 0), ('\u{11234}', '\u{11234}', 0, 0), ('\u{11236}',
+ '\u{11237}', 0, 0), ('\u{1123e}', '\u{1123e}', 0, 0), ('\u{112df}', '\u{112df}', 0, 0),
+ ('\u{112e3}', '\u{112ea}', 0, 0), ('\u{11300}', '\u{11301}', 0, 0), ('\u{1133b}',
+ '\u{1133c}', 0, 0), ('\u{11340}', '\u{11340}', 0, 0), ('\u{11366}', '\u{1136c}', 0, 0),
+ ('\u{11370}', '\u{11374}', 0, 0), ('\u{11438}', '\u{1143f}', 0, 0), ('\u{11442}',
+ '\u{11444}', 0, 0), ('\u{11446}', '\u{11446}', 0, 0), ('\u{1145e}', '\u{1145e}', 0, 0),
+ ('\u{114b3}', '\u{114b8}', 0, 0), ('\u{114ba}', '\u{114ba}', 0, 0), ('\u{114bf}',
+ '\u{114c0}', 0, 0), ('\u{114c2}', '\u{114c3}', 0, 0), ('\u{115b2}', '\u{115b5}', 0, 0),
+ ('\u{115bc}', '\u{115bd}', 0, 0), ('\u{115bf}', '\u{115c0}', 0, 0), ('\u{115dc}',
+ '\u{115dd}', 0, 0), ('\u{11633}', '\u{1163a}', 0, 0), ('\u{1163d}', '\u{1163d}', 0, 0),
+ ('\u{1163f}', '\u{11640}', 0, 0), ('\u{116ab}', '\u{116ab}', 0, 0), ('\u{116ad}',
+ '\u{116ad}', 0, 0), ('\u{116b0}', '\u{116b5}', 0, 0), ('\u{116b7}', '\u{116b7}', 0, 0),
+ ('\u{1171d}', '\u{1171f}', 0, 0), ('\u{11722}', '\u{11725}', 0, 0), ('\u{11727}',
+ '\u{1172b}', 0, 0), ('\u{1182f}', '\u{11837}', 0, 0), ('\u{11839}', '\u{1183a}', 0, 0),
+ ('\u{119d4}', '\u{119d7}', 0, 0), ('\u{119da}', '\u{119db}', 0, 0), ('\u{119e0}',
+ '\u{119e0}', 0, 0), ('\u{11a01}', '\u{11a0a}', 0, 0), ('\u{11a33}', '\u{11a38}', 0, 0),
+ ('\u{11a3b}', '\u{11a3e}', 0, 0), ('\u{11a47}', '\u{11a47}', 0, 0), ('\u{11a51}',
+ '\u{11a56}', 0, 0), ('\u{11a59}', '\u{11a5b}', 0, 0), ('\u{11a8a}', '\u{11a96}', 0, 0),
+ ('\u{11a98}', '\u{11a99}', 0, 0), ('\u{11c30}', '\u{11c36}', 0, 0), ('\u{11c38}',
+ '\u{11c3d}', 0, 0), ('\u{11c3f}', '\u{11c3f}', 0, 0), ('\u{11c92}', '\u{11ca7}', 0, 0),
+ ('\u{11caa}', '\u{11cb0}', 0, 0), ('\u{11cb2}', '\u{11cb3}', 0, 0), ('\u{11cb5}',
+ '\u{11cb6}', 0, 0), ('\u{11d31}', '\u{11d36}', 0, 0), ('\u{11d3a}', '\u{11d3a}', 0, 0),
+ ('\u{11d3c}', '\u{11d3d}', 0, 0), ('\u{11d3f}', '\u{11d45}', 0, 0), ('\u{11d47}',
+ '\u{11d47}', 0, 0), ('\u{11d90}', '\u{11d91}', 0, 0), ('\u{11d95}', '\u{11d95}', 0, 0),
+ ('\u{11d97}', '\u{11d97}', 0, 0), ('\u{11ef3}', '\u{11ef4}', 0, 0), ('\u{13430}',
+ '\u{13438}', 0, 0), ('\u{16af0}', '\u{16af4}', 0, 0), ('\u{16b30}', '\u{16b36}', 0, 0),
+ ('\u{16f4f}', '\u{16f4f}', 0, 0), ('\u{16f8f}', '\u{16f92}', 0, 0), ('\u{16fe0}',
+ '\u{16fe3}', 2, 2), ('\u{17000}', '\u{187f7}', 2, 2), ('\u{18800}', '\u{18af2}', 2, 2),
+ ('\u{1b000}', '\u{1b11e}', 2, 2), ('\u{1b150}', '\u{1b152}', 2, 2), ('\u{1b164}',
+ '\u{1b167}', 2, 2), ('\u{1b170}', '\u{1b2fb}', 2, 2), ('\u{1bc9d}', '\u{1bc9e}', 0, 0),
+ ('\u{1bca0}', '\u{1bca3}', 0, 0), ('\u{1d167}', '\u{1d169}', 0, 0), ('\u{1d173}',
+ '\u{1d182}', 0, 0), ('\u{1d185}', '\u{1d18b}', 0, 0), ('\u{1d1aa}', '\u{1d1ad}', 0, 0),
+ ('\u{1d242}', '\u{1d244}', 0, 0), ('\u{1da00}', '\u{1da36}', 0, 0), ('\u{1da3b}',
+ '\u{1da6c}', 0, 0), ('\u{1da75}', '\u{1da75}', 0, 0), ('\u{1da84}', '\u{1da84}', 0, 0),
+ ('\u{1da9b}', '\u{1da9f}', 0, 0), ('\u{1daa1}', '\u{1daaf}', 0, 0), ('\u{1e000}',
+ '\u{1e006}', 0, 0), ('\u{1e008}', '\u{1e018}', 0, 0), ('\u{1e01b}', '\u{1e021}', 0, 0),
+ ('\u{1e023}', '\u{1e024}', 0, 0), ('\u{1e026}', '\u{1e02a}', 0, 0), ('\u{1e130}',
+ '\u{1e136}', 0, 0), ('\u{1e2ec}', '\u{1e2ef}', 0, 0), ('\u{1e8d0}', '\u{1e8d6}', 0, 0),
+ ('\u{1e944}', '\u{1e94a}', 0, 0), ('\u{1f004}', '\u{1f004}', 2, 2), ('\u{1f0cf}',
+ '\u{1f0cf}', 2, 2), ('\u{1f100}', '\u{1f10a}', 1, 2), ('\u{1f110}', '\u{1f12d}', 1, 2),
+ ('\u{1f130}', '\u{1f169}', 1, 2), ('\u{1f170}', '\u{1f18d}', 1, 2), ('\u{1f18e}',
+ '\u{1f18e}', 2, 2), ('\u{1f18f}', '\u{1f190}', 1, 2), ('\u{1f191}', '\u{1f19a}', 2, 2),
+ ('\u{1f19b}', '\u{1f1ac}', 1, 2), ('\u{1f200}', '\u{1f202}', 2, 2), ('\u{1f210}',
+ '\u{1f23b}', 2, 2), ('\u{1f240}', '\u{1f248}', 2, 2), ('\u{1f250}', '\u{1f251}', 2, 2),
+ ('\u{1f260}', '\u{1f265}', 2, 2), ('\u{1f300}', '\u{1f320}', 2, 2), ('\u{1f32d}',
+ '\u{1f335}', 2, 2), ('\u{1f337}', '\u{1f37c}', 2, 2), ('\u{1f37e}', '\u{1f393}', 2, 2),
+ ('\u{1f3a0}', '\u{1f3ca}', 2, 2), ('\u{1f3cf}', '\u{1f3d3}', 2, 2), ('\u{1f3e0}',
+ '\u{1f3f0}', 2, 2), ('\u{1f3f4}', '\u{1f3f4}', 2, 2), ('\u{1f3f8}', '\u{1f43e}', 2, 2),
+ ('\u{1f440}', '\u{1f440}', 2, 2), ('\u{1f442}', '\u{1f4fc}', 2, 2), ('\u{1f4ff}',
+ '\u{1f53d}', 2, 2), ('\u{1f54b}', '\u{1f54e}', 2, 2), ('\u{1f550}', '\u{1f567}', 2, 2),
+ ('\u{1f57a}', '\u{1f57a}', 2, 2), ('\u{1f595}', '\u{1f596}', 2, 2), ('\u{1f5a4}',
+ '\u{1f5a4}', 2, 2), ('\u{1f5fb}', '\u{1f64f}', 2, 2), ('\u{1f680}', '\u{1f6c5}', 2, 2),
+ ('\u{1f6cc}', '\u{1f6cc}', 2, 2), ('\u{1f6d0}', '\u{1f6d2}', 2, 2), ('\u{1f6d5}',
+ '\u{1f6d5}', 2, 2), ('\u{1f6eb}', '\u{1f6ec}', 2, 2), ('\u{1f6f4}', '\u{1f6fa}', 2, 2),
+ ('\u{1f7e0}', '\u{1f7eb}', 2, 2), ('\u{1f90d}', '\u{1f971}', 2, 2), ('\u{1f973}',
+ '\u{1f976}', 2, 2), ('\u{1f97a}', '\u{1f9a2}', 2, 2), ('\u{1f9a5}', '\u{1f9aa}', 2, 2),
+ ('\u{1f9ae}', '\u{1f9ca}', 2, 2), ('\u{1f9cd}', '\u{1f9ff}', 2, 2), ('\u{1fa70}',
+ '\u{1fa73}', 2, 2), ('\u{1fa78}', '\u{1fa7a}', 2, 2), ('\u{1fa80}', '\u{1fa82}', 2, 2),
+ ('\u{1fa90}', '\u{1fa95}', 2, 2), ('\u{20000}', '\u{2fffd}', 2, 2), ('\u{30000}',
+ '\u{3fffd}', 2, 2), ('\u{e0001}', '\u{e0001}', 0, 0), ('\u{e0020}', '\u{e007f}', 0, 0),
+ ('\u{e0100}', '\u{e01ef}', 0, 0), ('\u{f0000}', '\u{ffffd}', 1, 2), ('\u{100000}',
+ '\u{10fffd}', 1, 2)
+ ];
+
+}
+
diff --git a/unicode-width/src/tests.rs b/unicode-width/src/tests.rs
new file mode 100644
index 0000000..72808c6
--- /dev/null
+++ b/unicode-width/src/tests.rs
@@ -0,0 +1,175 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature = "bench")]
+use std::iter;
+#[cfg(feature = "bench")]
+use test::{self, Bencher};
+#[cfg(feature = "bench")]
+use super::UnicodeWidthChar;
+
+use std::prelude::v1::*;
+
+#[cfg(feature = "bench")]
+#[bench]
+fn cargo(b: &mut Bencher) {
+ let string = iter::repeat('a').take(4096).collect::<String>();
+
+ b.iter(|| {
+ for c in string.chars() {
+ test::black_box(UnicodeWidthChar::width(c));
+ }
+ });
+}
+
+#[cfg(feature = "bench")]
+#[bench]
+#[allow(deprecated)]
+fn stdlib(b: &mut Bencher) {
+ let string = iter::repeat('a').take(4096).collect::<String>();
+
+ b.iter(|| {
+ for c in string.chars() {
+ test::black_box(c.width());
+ }
+ });
+}
+
+#[cfg(feature = "bench")]
+#[bench]
+fn simple_if(b: &mut Bencher) {
+ let string = iter::repeat('a').take(4096).collect::<String>();
+
+ b.iter(|| {
+ for c in string.chars() {
+ test::black_box(simple_width_if(c));
+ }
+ });
+}
+
+#[cfg(feature = "bench")]
+#[bench]
+fn simple_match(b: &mut Bencher) {
+ let string = iter::repeat('a').take(4096).collect::<String>();
+
+ b.iter(|| {
+ for c in string.chars() {
+ test::black_box(simple_width_match(c));
+ }
+ });
+}
+
+#[cfg(feature = "bench")]
+#[inline]
+fn simple_width_if(c: char) -> Option<usize> {
+ let cu = c as u32;
+ if cu < 127 {
+ if cu > 31 {
+ Some(1)
+ } else if cu == 0 {
+ Some(0)
+ } else {
+ None
+ }
+ } else {
+ UnicodeWidthChar::width(c)
+ }
+}
+
+#[cfg(feature = "bench")]
+#[inline]
+fn simple_width_match(c: char) -> Option<usize> {
+ match c as u32 {
+ cu if cu == 0 => Some(0),
+ cu if cu < 0x20 => None,
+ cu if cu < 0x7f => Some(1),
+ _ => UnicodeWidthChar::width(c)
+ }
+}
+
+#[test]
+fn test_str() {
+ use super::UnicodeWidthStr;
+
+ assert_eq!(UnicodeWidthStr::width("hello"), 10);
+ assert_eq!("hello".width_cjk(), 10);
+ assert_eq!(UnicodeWidthStr::width("\0\0\0\x01\x01"), 0);
+ assert_eq!("\0\0\0\x01\x01".width_cjk(), 0);
+ assert_eq!(UnicodeWidthStr::width(""), 0);
+ assert_eq!("".width_cjk(), 0);
+ assert_eq!(UnicodeWidthStr::width("\u{2081}\u{2082}\u{2083}\u{2084}"), 4);
+ assert_eq!("\u{2081}\u{2082}\u{2083}\u{2084}".width_cjk(), 8);
+}
+
+#[test]
+fn test_emoji() {
+ // Example from the README.
+ use super::UnicodeWidthStr;
+
+ assert_eq!(UnicodeWidthStr::width("👩"), 2); // Woman
+ assert_eq!(UnicodeWidthStr::width("🔬"), 2); // Microscope
+ assert_eq!(UnicodeWidthStr::width("👩‍🔬"), 4); // Woman scientist
+}
+
+#[test]
+fn test_char() {
+ use super::UnicodeWidthChar;
+ #[cfg(feature = "no_std")]
+ use core::option::Option::{Some, None};
+
+ assert_eq!(UnicodeWidthChar::width('h'), Some(2));
+ assert_eq!('h'.width_cjk(), Some(2));
+ assert_eq!(UnicodeWidthChar::width('\x00'), Some(0));
+ assert_eq!('\x00'.width_cjk(), Some(0));
+ assert_eq!(UnicodeWidthChar::width('\x01'), None);
+ assert_eq!('\x01'.width_cjk(), None);
+ assert_eq!(UnicodeWidthChar::width('\u{2081}'), Some(1));
+ assert_eq!('\u{2081}'.width_cjk(), Some(2));
+}
+
+#[test]
+fn test_char2() {
+ use super::UnicodeWidthChar;
+ #[cfg(feature = "no_std")]
+ use core::option::Option::{Some, None};
+
+ assert_eq!(UnicodeWidthChar::width('\x00'),Some(0));
+ assert_eq!('\x00'.width_cjk(),Some(0));
+
+ assert_eq!(UnicodeWidthChar::width('\x0A'),None);
+ assert_eq!('\x0A'.width_cjk(),None);
+
+ assert_eq!(UnicodeWidthChar::width('w'),Some(1));
+ assert_eq!('w'.width_cjk(),Some(1));
+
+ assert_eq!(UnicodeWidthChar::width('h'),Some(2));
+ assert_eq!('h'.width_cjk(),Some(2));
+
+ assert_eq!(UnicodeWidthChar::width('\u{AD}'),Some(1));
+ assert_eq!('\u{AD}'.width_cjk(),Some(1));
+
+ assert_eq!(UnicodeWidthChar::width('\u{1160}'),Some(0));
+ assert_eq!('\u{1160}'.width_cjk(),Some(0));
+
+ assert_eq!(UnicodeWidthChar::width('\u{a1}'),Some(1));
+ assert_eq!('\u{a1}'.width_cjk(),Some(2));
+
+ assert_eq!(UnicodeWidthChar::width('\u{300}'),Some(0));
+ assert_eq!('\u{300}'.width_cjk(),Some(0));
+}
+
+#[test]
+fn unicode_12() {
+ use super::UnicodeWidthChar;
+ #[cfg(feature = "no_std")]
+ use core::option::Option::{Some, None};
+
+ assert_eq!(UnicodeWidthChar::width('\u{1F971}'), Some(2));
+}
diff --git a/unicode-xid/.gitignore b/unicode-xid/.gitignore
new file mode 100644
index 0000000..5cdcdba
--- /dev/null
+++ b/unicode-xid/.gitignore
@@ -0,0 +1,3 @@
+target
+Cargo.lock
+scripts/tmp
diff --git a/unicode-xid/.travis.yml b/unicode-xid/.travis.yml
new file mode 100644
index 0000000..d9c5c2a
--- /dev/null
+++ b/unicode-xid/.travis.yml
@@ -0,0 +1,25 @@
+language: rust
+rust: 'nightly'
+sudo: false
+script:
+ - cargo build --verbose --features bench
+ - cargo test --verbose --features bench
+ - cargo bench --verbose --features bench
+ - cargo clean
+ - cargo build --verbose
+ - cargo test --verbose
+ - rustdoc --test README.md -L target/debug -L target/debug/deps
+ - cargo doc
+after_success: |
+ [ $TRAVIS_BRANCH = master ] &&
+ [ $TRAVIS_PULL_REQUEST = false ] &&
+ echo '<meta http-equiv=refresh content=0;url=unicode_xid/index.html>' > target/doc/index.html &&
+ pip install ghp-import --user $USER &&
+ $HOME/.local/bin/ghp-import -n target/doc &&
+ git push -qf https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
+env:
+ global:
+ secure: gTlge+/OQlVkV0R+RThWXeN0aknmS7iUTPBMYKJyRdLz7T2vubw3w80a2CVE87JlpV87A5cVGD+LgR+AhYrhKtvqHb1brMDd99gylBBi2DfV7YapDSwSCuFgVR+FjZfJRcXBtI8po5urUZ84V0WLzRX8SyWqWgoD3oCkSL3Wp3w=
+notifications:
+ email:
+ on_success: never
diff --git a/unicode-xid/COPYRIGHT b/unicode-xid/COPYRIGHT
new file mode 100644
index 0000000..b286ec1
--- /dev/null
+++ b/unicode-xid/COPYRIGHT
@@ -0,0 +1,7 @@
+Licensed under the Apache License, Version 2.0
+<LICENSE-APACHE or
+http://www.apache.org/licenses/LICENSE-2.0> or the MIT
+license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
+at your option. All files in the project carrying such
+notice may not be copied, modified, or distributed except
+according to those terms.
diff --git a/unicode-xid/Cargo.toml b/unicode-xid/Cargo.toml
new file mode 100644
index 0000000..e813762
--- /dev/null
+++ b/unicode-xid/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+
+name = "unicode-xid"
+version = "0.2.0"
+authors = ["erick.tryzelaar <erick.tryzelaar@gmail.com>",
+ "kwantam <kwantam@gmail.com>",
+ ]
+
+homepage = "https://github.com/unicode-rs/unicode-xid"
+repository = "https://github.com/unicode-rs/unicode-xid"
+documentation = "https://unicode-rs.github.io/unicode-xid"
+license = "MIT OR Apache-2.0"
+keywords = ["text", "unicode", "xid"]
+readme = "README.md"
+description = """
+Determine whether characters have the XID_Start
+or XID_Continue properties according to
+Unicode Standard Annex #31.
+"""
+exclude = ["/scripts/*", "/.travis.yml"]
+
+[badges]
+travis-ci = { repository = "unicode-rs/unicode-xid" }
+
+[features]
+default = []
+no_std = []
+bench = []
diff --git a/unicode-xid/LICENSE-APACHE b/unicode-xid/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/unicode-xid/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/unicode-xid/LICENSE-MIT b/unicode-xid/LICENSE-MIT
new file mode 100644
index 0000000..e69282e
--- /dev/null
+++ b/unicode-xid/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015 The Rust Project Developers
+
+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/unicode-xid/README.md b/unicode-xid/README.md
new file mode 100644
index 0000000..3c1ef2a
--- /dev/null
+++ b/unicode-xid/README.md
@@ -0,0 +1,44 @@
+# unicode-xid
+
+Determine if a `char` is a valid identifier for a parser and/or lexer according to
+[Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) rules.
+
+[![Build Status](https://travis-ci.org/unicode-rs/unicode-xid.svg)](https://travis-ci.org/unicode-rs/unicode-xid)
+
+[Documentation](https://unicode-rs.github.io/unicode-xid/unicode_xid/index.html)
+
+```rust
+extern crate unicode_xid;
+
+use unicode_xid::UnicodeXID;
+
+fn main() {
+ let ch = 'a';
+ println!("Is {} a valid start of an identifier? {}", ch, UnicodeXID::is_xid_start(ch));
+}
+```
+
+# features
+
+unicode-xid supports a `no_std` feature. This eliminates dependence
+on std, and instead uses equivalent functions from core.
+
+# crates.io
+
+You can use this package in your project by adding the following
+to your `Cargo.toml`:
+
+```toml
+[dependencies]
+unicode-xid = "0.1.0"
+```
+
+# changelog
+
+## 0.2.0
+
+- Update to Unicode 12.1.0.
+
+## 0.1.0
+
+- Initial release.
diff --git a/unicode-xid/scripts/unicode.py b/unicode-xid/scripts/unicode.py
new file mode 100755
index 0000000..393f901
--- /dev/null
+++ b/unicode-xid/scripts/unicode.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+#
+# Copyright 2011-2015 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+# This script uses the following Unicode tables:
+# - DerivedCoreProperties.txt
+# - ReadMe.txt
+#
+# Since this should not require frequent updates, we just store this
+# out-of-line and check the unicode.rs file into git.
+
+import fileinput, re, os, sys
+
+preamble = '''// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly
+
+#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
+'''
+
+def fetch(f):
+ if not os.path.exists(os.path.basename(f)):
+ os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s"
+ % f)
+
+ if not os.path.exists(os.path.basename(f)):
+ sys.stderr.write("cannot load %s" % f)
+ exit(1)
+
+def group_cat(cat):
+ cat_out = []
+ letters = sorted(set(cat))
+ cur_start = letters.pop(0)
+ cur_end = cur_start
+ for letter in letters:
+ assert letter > cur_end, \
+ "cur_end: %s, letter: %s" % (hex(cur_end), hex(letter))
+ if letter == cur_end + 1:
+ cur_end = letter
+ else:
+ cat_out.append((cur_start, cur_end))
+ cur_start = cur_end = letter
+ cat_out.append((cur_start, cur_end))
+ return cat_out
+
+def ungroup_cat(cat):
+ cat_out = []
+ for (lo, hi) in cat:
+ while lo <= hi:
+ cat_out.append(lo)
+ lo += 1
+ return cat_out
+
+def format_table_content(f, content, indent):
+ line = " "*indent
+ first = True
+ for chunk in content.split(","):
+ if len(line) + len(chunk) < 98:
+ if first:
+ line += chunk
+ else:
+ line += ", " + chunk
+ first = False
+ else:
+ f.write(line + ",\n")
+ line = " "*indent + chunk
+ f.write(line)
+
+def load_properties(f, interestingprops):
+ fetch(f)
+ props = {}
+ re1 = re.compile("^ *([0-9A-F]+) *; *(\w+)")
+ re2 = re.compile("^ *([0-9A-F]+)\.\.([0-9A-F]+) *; *(\w+)")
+
+ for line in fileinput.input(os.path.basename(f)):
+ prop = None
+ d_lo = 0
+ d_hi = 0
+ m = re1.match(line)
+ if m:
+ d_lo = m.group(1)
+ d_hi = m.group(1)
+ prop = m.group(2)
+ else:
+ m = re2.match(line)
+ if m:
+ d_lo = m.group(1)
+ d_hi = m.group(2)
+ prop = m.group(3)
+ else:
+ continue
+ if interestingprops and prop not in interestingprops:
+ continue
+ d_lo = int(d_lo, 16)
+ d_hi = int(d_hi, 16)
+ if prop not in props:
+ props[prop] = []
+ props[prop].append((d_lo, d_hi))
+
+ # optimize if possible
+ for prop in props:
+ props[prop] = group_cat(ungroup_cat(props[prop]))
+
+ return props
+
+def escape_char(c):
+ return "'\\u{%x}'" % c
+
+def emit_bsearch_range_table(f):
+ f.write("""
+fn bsearch_range_table(c: char, r: &[(char,char)]) -> bool {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+
+ r.binary_search_by(|&(lo,hi)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }).is_ok()
+}\n
+""")
+
+def emit_table(f, name, t_data, t_type = "&[(char, char)]", is_pub=True,
+ pfun=lambda x: "(%s,%s)" % (escape_char(x[0]), escape_char(x[1])), is_const=True):
+ pub_string = "const"
+ if not is_const:
+ pub_string = "let"
+ if is_pub:
+ pub_string = "pub " + pub_string
+ f.write(" %s %s: %s = &[\n" % (pub_string, name, t_type))
+ data = ""
+ first = True
+ for dat in t_data:
+ if not first:
+ data += ","
+ first = False
+ data += pfun(dat)
+ format_table_content(f, data, 8)
+ f.write("\n ];\n\n")
+
+def emit_property_module(f, mod, tbl, emit):
+ f.write("pub mod %s {\n" % mod)
+ for cat in sorted(emit):
+ emit_table(f, "%s_table" % cat, tbl[cat])
+ f.write(" pub fn %s(c: char) -> bool {\n" % cat)
+ f.write(" super::bsearch_range_table(c, %s_table)\n" % cat)
+ f.write(" }\n\n")
+ f.write("}\n\n")
+
+if __name__ == "__main__":
+ r = "tables.rs"
+ if os.path.exists(r):
+ os.remove(r)
+ with open(r, "w") as rf:
+ # write the file's preamble
+ rf.write(preamble)
+
+ # download and parse all the data
+ fetch("ReadMe.txt")
+ with open("ReadMe.txt") as readme:
+ pattern = "for Version (\d+)\.(\d+)\.(\d+) of the Unicode"
+ unicode_version = re.search(pattern, readme.read()).groups()
+ rf.write("""
+/// The version of [Unicode](http://www.unicode.org/)
+/// that this version of unicode-xid is based on.
+pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
+""" % unicode_version)
+ emit_bsearch_range_table(rf)
+
+ want_derived = ["XID_Start", "XID_Continue"]
+ derived = load_properties("DerivedCoreProperties.txt", want_derived)
+ emit_property_module(rf, "derived_property", derived, want_derived)
diff --git a/unicode-xid/src/lib.rs b/unicode-xid/src/lib.rs
new file mode 100644
index 0000000..7dd95ba
--- /dev/null
+++ b/unicode-xid/src/lib.rs
@@ -0,0 +1,87 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Determine if a `char` is a valid identifier for a parser and/or lexer according to
+//! [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) rules.
+//!
+//! ```rust
+//! extern crate unicode_xid;
+//!
+//! use unicode_xid::UnicodeXID;
+//!
+//! fn main() {
+//! let ch = 'a';
+//! println!("Is {} a valid start of an identifier? {}", ch, UnicodeXID::is_xid_start(ch));
+//! }
+//! ```
+//!
+//! # features
+//!
+//! unicode-xid supports a `no_std` feature. This eliminates dependence
+//! on std, and instead uses equivalent functions from core.
+//!
+//! # crates.io
+//!
+//! You can use this package in your project by adding the following
+//! to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! unicode-xid = "0.0.4"
+//! ```
+
+#![deny(missing_docs, unsafe_code)]
+#![doc(html_logo_url = "https://unicode-rs.github.io/unicode-rs_sm.png",
+ html_favicon_url = "https://unicode-rs.github.io/unicode-rs_sm.png")]
+
+#![no_std]
+#![cfg_attr(feature = "bench", feature(test, unicode_internals))]
+
+#[cfg(test)]
+#[macro_use]
+extern crate std;
+
+#[cfg(feature = "bench")]
+extern crate test;
+
+use tables::derived_property;
+pub use tables::UNICODE_VERSION;
+
+mod tables;
+
+#[cfg(test)]
+mod tests;
+
+/// Methods for determining if a character is a valid identifier character.
+pub trait UnicodeXID {
+ /// Returns whether the specified character satisfies the 'XID_Start'
+ /// Unicode property.
+ ///
+ /// 'XID_Start' is a Unicode Derived Property specified in
+ /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
+ /// mostly similar to ID_Start but modified for closure under NFKx.
+ fn is_xid_start(self) -> bool;
+
+ /// Returns whether the specified `char` satisfies the 'XID_Continue'
+ /// Unicode property.
+ ///
+ /// 'XID_Continue' is a Unicode Derived Property specified in
+ /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
+ /// mostly similar to 'ID_Continue' but modified for closure under NFKx.
+ fn is_xid_continue(self) -> bool;
+}
+
+impl UnicodeXID for char {
+ #[inline]
+ fn is_xid_start(self) -> bool { derived_property::XID_Start(self) }
+
+ #[inline]
+ fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) }
+}
diff --git a/unicode-xid/src/tables.rs b/unicode-xid/src/tables.rs
new file mode 100644
index 0000000..edd51d0
--- /dev/null
+++ b/unicode-xid/src/tables.rs
@@ -0,0 +1,451 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly
+
+#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
+
+/// The version of [Unicode](http://www.unicode.org/)
+/// that this version of unicode-xid is based on.
+pub const UNICODE_VERSION: (u64, u64, u64) = (12, 1, 0);
+
+fn bsearch_range_table(c: char, r: &[(char,char)]) -> bool {
+ use core::cmp::Ordering::{Equal, Less, Greater};
+
+ r.binary_search_by(|&(lo,hi)| {
+ if lo <= c && c <= hi { Equal }
+ else if hi < c { Less }
+ else { Greater }
+ }).is_ok()
+}
+
+pub mod derived_property {
+ pub const XID_Continue_table: &[(char, char)] = &[
+ ('\u{30}', '\u{39}'), ('\u{41}', '\u{5a}'), ('\u{5f}', '\u{5f}'), ('\u{61}', '\u{7a}'),
+ ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), ('\u{b7}', '\u{b7}'), ('\u{ba}', '\u{ba}'),
+ ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'), ('\u{2c6}', '\u{2d1}'),
+ ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', '\u{2ee}'), ('\u{300}',
+ '\u{374}'), ('\u{376}', '\u{377}'), ('\u{37b}', '\u{37d}'), ('\u{37f}', '\u{37f}'),
+ ('\u{386}', '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}',
+ '\u{3f5}'), ('\u{3f7}', '\u{481}'), ('\u{483}', '\u{487}'), ('\u{48a}', '\u{52f}'),
+ ('\u{531}', '\u{556}'), ('\u{559}', '\u{559}'), ('\u{560}', '\u{588}'), ('\u{591}',
+ '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'),
+ ('\u{5c7}', '\u{5c7}'), ('\u{5d0}', '\u{5ea}'), ('\u{5ef}', '\u{5f2}'), ('\u{610}',
+ '\u{61a}'), ('\u{620}', '\u{669}'), ('\u{66e}', '\u{6d3}'), ('\u{6d5}', '\u{6dc}'),
+ ('\u{6df}', '\u{6e8}'), ('\u{6ea}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), ('\u{710}',
+ '\u{74a}'), ('\u{74d}', '\u{7b1}'), ('\u{7c0}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'),
+ ('\u{7fd}', '\u{7fd}'), ('\u{800}', '\u{82d}'), ('\u{840}', '\u{85b}'), ('\u{860}',
+ '\u{86a}'), ('\u{8a0}', '\u{8b4}'), ('\u{8b6}', '\u{8bd}'), ('\u{8d3}', '\u{8e1}'),
+ ('\u{8e3}', '\u{963}'), ('\u{966}', '\u{96f}'), ('\u{971}', '\u{983}'), ('\u{985}',
+ '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', '\u{9a8}'), ('\u{9aa}', '\u{9b0}'),
+ ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), ('\u{9bc}', '\u{9c4}'), ('\u{9c7}',
+ '\u{9c8}'), ('\u{9cb}', '\u{9ce}'), ('\u{9d7}', '\u{9d7}'), ('\u{9dc}', '\u{9dd}'),
+ ('\u{9df}', '\u{9e3}'), ('\u{9e6}', '\u{9f1}'), ('\u{9fc}', '\u{9fc}'), ('\u{9fe}',
+ '\u{9fe}'), ('\u{a01}', '\u{a03}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'),
+ ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}',
+ '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a3c}', '\u{a3c}'), ('\u{a3e}', '\u{a42}'),
+ ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a59}',
+ '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a66}', '\u{a75}'), ('\u{a81}', '\u{a83}'),
+ ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), ('\u{aaa}',
+ '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abc}', '\u{ac5}'),
+ ('\u{ac7}', '\u{ac9}'), ('\u{acb}', '\u{acd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}',
+ '\u{ae3}'), ('\u{ae6}', '\u{aef}'), ('\u{af9}', '\u{aff}'), ('\u{b01}', '\u{b03}'),
+ ('\u{b05}', '\u{b0c}'), ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}',
+ '\u{b30}'), ('\u{b32}', '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3c}', '\u{b44}'),
+ ('\u{b47}', '\u{b48}'), ('\u{b4b}', '\u{b4d}'), ('\u{b56}', '\u{b57}'), ('\u{b5c}',
+ '\u{b5d}'), ('\u{b5f}', '\u{b63}'), ('\u{b66}', '\u{b6f}'), ('\u{b71}', '\u{b71}'),
+ ('\u{b82}', '\u{b83}'), ('\u{b85}', '\u{b8a}'), ('\u{b8e}', '\u{b90}'), ('\u{b92}',
+ '\u{b95}'), ('\u{b99}', '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', '\u{b9f}'),
+ ('\u{ba3}', '\u{ba4}'), ('\u{ba8}', '\u{baa}'), ('\u{bae}', '\u{bb9}'), ('\u{bbe}',
+ '\u{bc2}'), ('\u{bc6}', '\u{bc8}'), ('\u{bca}', '\u{bcd}'), ('\u{bd0}', '\u{bd0}'),
+ ('\u{bd7}', '\u{bd7}'), ('\u{be6}', '\u{bef}'), ('\u{c00}', '\u{c0c}'), ('\u{c0e}',
+ '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), ('\u{c3d}', '\u{c44}'),
+ ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'), ('\u{c58}',
+ '\u{c5a}'), ('\u{c60}', '\u{c63}'), ('\u{c66}', '\u{c6f}'), ('\u{c80}', '\u{c83}'),
+ ('\u{c85}', '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}',
+ '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), ('\u{cbc}', '\u{cc4}'), ('\u{cc6}', '\u{cc8}'),
+ ('\u{cca}', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}',
+ '\u{ce3}'), ('\u{ce6}', '\u{cef}'), ('\u{cf1}', '\u{cf2}'), ('\u{d00}', '\u{d03}'),
+ ('\u{d05}', '\u{d0c}'), ('\u{d0e}', '\u{d10}'), ('\u{d12}', '\u{d44}'), ('\u{d46}',
+ '\u{d48}'), ('\u{d4a}', '\u{d4e}'), ('\u{d54}', '\u{d57}'), ('\u{d5f}', '\u{d63}'),
+ ('\u{d66}', '\u{d6f}'), ('\u{d7a}', '\u{d7f}'), ('\u{d82}', '\u{d83}'), ('\u{d85}',
+ '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', '\u{dbb}'), ('\u{dbd}', '\u{dbd}'),
+ ('\u{dc0}', '\u{dc6}'), ('\u{dca}', '\u{dca}'), ('\u{dcf}', '\u{dd4}'), ('\u{dd6}',
+ '\u{dd6}'), ('\u{dd8}', '\u{ddf}'), ('\u{de6}', '\u{def}'), ('\u{df2}', '\u{df3}'),
+ ('\u{e01}', '\u{e3a}'), ('\u{e40}', '\u{e4e}'), ('\u{e50}', '\u{e59}'), ('\u{e81}',
+ '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e86}', '\u{e8a}'), ('\u{e8c}', '\u{ea3}'),
+ ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{ebd}'), ('\u{ec0}', '\u{ec4}'), ('\u{ec6}',
+ '\u{ec6}'), ('\u{ec8}', '\u{ecd}'), ('\u{ed0}', '\u{ed9}'), ('\u{edc}', '\u{edf}'),
+ ('\u{f00}', '\u{f00}'), ('\u{f18}', '\u{f19}'), ('\u{f20}', '\u{f29}'), ('\u{f35}',
+ '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), ('\u{f3e}', '\u{f47}'),
+ ('\u{f49}', '\u{f6c}'), ('\u{f71}', '\u{f84}'), ('\u{f86}', '\u{f97}'), ('\u{f99}',
+ '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), ('\u{1000}', '\u{1049}'), ('\u{1050}', '\u{109d}'),
+ ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{10d0}',
+ '\u{10fa}'), ('\u{10fc}', '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', '\u{1256}'),
+ ('\u{1258}', '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), ('\u{128a}',
+ '\u{128d}'), ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', '\u{12be}'),
+ ('\u{12c0}', '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), ('\u{12d8}',
+ '\u{1310}'), ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{135d}', '\u{135f}'),
+ ('\u{1369}', '\u{1371}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', '\u{13f5}'), ('\u{13f8}',
+ '\u{13fd}'), ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'),
+ ('\u{16a0}', '\u{16ea}'), ('\u{16ee}', '\u{16f8}'), ('\u{1700}', '\u{170c}'), ('\u{170e}',
+ '\u{1714}'), ('\u{1720}', '\u{1734}'), ('\u{1740}', '\u{1753}'), ('\u{1760}', '\u{176c}'),
+ ('\u{176e}', '\u{1770}'), ('\u{1772}', '\u{1773}'), ('\u{1780}', '\u{17d3}'), ('\u{17d7}',
+ '\u{17d7}'), ('\u{17dc}', '\u{17dd}'), ('\u{17e0}', '\u{17e9}'), ('\u{180b}', '\u{180d}'),
+ ('\u{1810}', '\u{1819}'), ('\u{1820}', '\u{1878}'), ('\u{1880}', '\u{18aa}'), ('\u{18b0}',
+ '\u{18f5}'), ('\u{1900}', '\u{191e}'), ('\u{1920}', '\u{192b}'), ('\u{1930}', '\u{193b}'),
+ ('\u{1946}', '\u{196d}'), ('\u{1970}', '\u{1974}'), ('\u{1980}', '\u{19ab}'), ('\u{19b0}',
+ '\u{19c9}'), ('\u{19d0}', '\u{19da}'), ('\u{1a00}', '\u{1a1b}'), ('\u{1a20}', '\u{1a5e}'),
+ ('\u{1a60}', '\u{1a7c}'), ('\u{1a7f}', '\u{1a89}'), ('\u{1a90}', '\u{1a99}'), ('\u{1aa7}',
+ '\u{1aa7}'), ('\u{1ab0}', '\u{1abd}'), ('\u{1b00}', '\u{1b4b}'), ('\u{1b50}', '\u{1b59}'),
+ ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', '\u{1bf3}'), ('\u{1c00}', '\u{1c37}'), ('\u{1c40}',
+ '\u{1c49}'), ('\u{1c4d}', '\u{1c7d}'), ('\u{1c80}', '\u{1c88}'), ('\u{1c90}', '\u{1cba}'),
+ ('\u{1cbd}', '\u{1cbf}'), ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1cfa}'), ('\u{1d00}',
+ '\u{1df9}'), ('\u{1dfb}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'),
+ ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}',
+ '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'),
+ ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}',
+ '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'),
+ ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), ('\u{203f}', '\u{2040}'), ('\u{2054}',
+ '\u{2054}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'),
+ ('\u{20d0}', '\u{20dc}'), ('\u{20e1}', '\u{20e1}'), ('\u{20e5}', '\u{20f0}'), ('\u{2102}',
+ '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}', '\u{2115}'),
+ ('\u{2118}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', '\u{2126}'), ('\u{2128}',
+ '\u{2128}'), ('\u{212a}', '\u{2139}'), ('\u{213c}', '\u{213f}'), ('\u{2145}', '\u{2149}'),
+ ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2188}'), ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}',
+ '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'),
+ ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}',
+ '\u{2d6f}'), ('\u{2d7f}', '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', '\u{2dae}'),
+ ('\u{2db0}', '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}',
+ '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), ('\u{2de0}', '\u{2dff}'),
+ ('\u{3005}', '\u{3007}'), ('\u{3021}', '\u{302f}'), ('\u{3031}', '\u{3035}'), ('\u{3038}',
+ '\u{303c}'), ('\u{3041}', '\u{3096}'), ('\u{3099}', '\u{309a}'), ('\u{309d}', '\u{309f}'),
+ ('\u{30a1}', '\u{30fa}'), ('\u{30fc}', '\u{30ff}'), ('\u{3105}', '\u{312f}'), ('\u{3131}',
+ '\u{318e}'), ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'),
+ ('\u{4e00}', '\u{9fef}'), ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), ('\u{a500}',
+ '\u{a60c}'), ('\u{a610}', '\u{a62b}'), ('\u{a640}', '\u{a66f}'), ('\u{a674}', '\u{a67d}'),
+ ('\u{a67f}', '\u{a6f1}'), ('\u{a717}', '\u{a71f}'), ('\u{a722}', '\u{a788}'), ('\u{a78b}',
+ '\u{a7bf}'), ('\u{a7c2}', '\u{a7c6}'), ('\u{a7f7}', '\u{a827}'), ('\u{a840}', '\u{a873}'),
+ ('\u{a880}', '\u{a8c5}'), ('\u{a8d0}', '\u{a8d9}'), ('\u{a8e0}', '\u{a8f7}'), ('\u{a8fb}',
+ '\u{a8fb}'), ('\u{a8fd}', '\u{a92d}'), ('\u{a930}', '\u{a953}'), ('\u{a960}', '\u{a97c}'),
+ ('\u{a980}', '\u{a9c0}'), ('\u{a9cf}', '\u{a9d9}'), ('\u{a9e0}', '\u{a9fe}'), ('\u{aa00}',
+ '\u{aa36}'), ('\u{aa40}', '\u{aa4d}'), ('\u{aa50}', '\u{aa59}'), ('\u{aa60}', '\u{aa76}'),
+ ('\u{aa7a}', '\u{aac2}'), ('\u{aadb}', '\u{aadd}'), ('\u{aae0}', '\u{aaef}'), ('\u{aaf2}',
+ '\u{aaf6}'), ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'),
+ ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}',
+ '\u{ab67}'), ('\u{ab70}', '\u{abea}'), ('\u{abec}', '\u{abed}'), ('\u{abf0}', '\u{abf9}'),
+ ('\u{ac00}', '\u{d7a3}'), ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}',
+ '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'),
+ ('\u{fb1d}', '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}',
+ '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'),
+ ('\u{fbd3}', '\u{fc5d}'), ('\u{fc64}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}',
+ '\u{fdc7}'), ('\u{fdf0}', '\u{fdf9}'), ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', '\u{fe2f}'),
+ ('\u{fe33}', '\u{fe34}'), ('\u{fe4d}', '\u{fe4f}'), ('\u{fe71}', '\u{fe71}'), ('\u{fe73}',
+ '\u{fe73}'), ('\u{fe77}', '\u{fe77}'), ('\u{fe79}', '\u{fe79}'), ('\u{fe7b}', '\u{fe7b}'),
+ ('\u{fe7d}', '\u{fe7d}'), ('\u{fe7f}', '\u{fefc}'), ('\u{ff10}', '\u{ff19}'), ('\u{ff21}',
+ '\u{ff3a}'), ('\u{ff3f}', '\u{ff3f}'), ('\u{ff41}', '\u{ff5a}'), ('\u{ff66}', '\u{ffbe}'),
+ ('\u{ffc2}', '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}',
+ '\u{ffdc}'), ('\u{10000}', '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}',
+ '\u{1003a}'), ('\u{1003c}', '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}',
+ '\u{1005d}'), ('\u{10080}', '\u{100fa}'), ('\u{10140}', '\u{10174}'), ('\u{101fd}',
+ '\u{101fd}'), ('\u{10280}', '\u{1029c}'), ('\u{102a0}', '\u{102d0}'), ('\u{102e0}',
+ '\u{102e0}'), ('\u{10300}', '\u{1031f}'), ('\u{1032d}', '\u{1034a}'), ('\u{10350}',
+ '\u{1037a}'), ('\u{10380}', '\u{1039d}'), ('\u{103a0}', '\u{103c3}'), ('\u{103c8}',
+ '\u{103cf}'), ('\u{103d1}', '\u{103d5}'), ('\u{10400}', '\u{1049d}'), ('\u{104a0}',
+ '\u{104a9}'), ('\u{104b0}', '\u{104d3}'), ('\u{104d8}', '\u{104fb}'), ('\u{10500}',
+ '\u{10527}'), ('\u{10530}', '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}',
+ '\u{10755}'), ('\u{10760}', '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}',
+ '\u{10808}'), ('\u{1080a}', '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}',
+ '\u{1083c}'), ('\u{1083f}', '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}',
+ '\u{1089e}'), ('\u{108e0}', '\u{108f2}'), ('\u{108f4}', '\u{108f5}'), ('\u{10900}',
+ '\u{10915}'), ('\u{10920}', '\u{10939}'), ('\u{10980}', '\u{109b7}'), ('\u{109be}',
+ '\u{109bf}'), ('\u{10a00}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}',
+ '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), ('\u{10a19}', '\u{10a35}'), ('\u{10a38}',
+ '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}',
+ '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', '\u{10ae6}'), ('\u{10b00}',
+ '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', '\u{10b72}'), ('\u{10b80}',
+ '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), ('\u{10c80}', '\u{10cb2}'), ('\u{10cc0}',
+ '\u{10cf2}'), ('\u{10d00}', '\u{10d27}'), ('\u{10d30}', '\u{10d39}'), ('\u{10f00}',
+ '\u{10f1c}'), ('\u{10f27}', '\u{10f27}'), ('\u{10f30}', '\u{10f50}'), ('\u{10fe0}',
+ '\u{10ff6}'), ('\u{11000}', '\u{11046}'), ('\u{11066}', '\u{1106f}'), ('\u{1107f}',
+ '\u{110ba}'), ('\u{110d0}', '\u{110e8}'), ('\u{110f0}', '\u{110f9}'), ('\u{11100}',
+ '\u{11134}'), ('\u{11136}', '\u{1113f}'), ('\u{11144}', '\u{11146}'), ('\u{11150}',
+ '\u{11173}'), ('\u{11176}', '\u{11176}'), ('\u{11180}', '\u{111c4}'), ('\u{111c9}',
+ '\u{111cc}'), ('\u{111d0}', '\u{111da}'), ('\u{111dc}', '\u{111dc}'), ('\u{11200}',
+ '\u{11211}'), ('\u{11213}', '\u{11237}'), ('\u{1123e}', '\u{1123e}'), ('\u{11280}',
+ '\u{11286}'), ('\u{11288}', '\u{11288}'), ('\u{1128a}', '\u{1128d}'), ('\u{1128f}',
+ '\u{1129d}'), ('\u{1129f}', '\u{112a8}'), ('\u{112b0}', '\u{112ea}'), ('\u{112f0}',
+ '\u{112f9}'), ('\u{11300}', '\u{11303}'), ('\u{11305}', '\u{1130c}'), ('\u{1130f}',
+ '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'), ('\u{11332}',
+ '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133b}', '\u{11344}'), ('\u{11347}',
+ '\u{11348}'), ('\u{1134b}', '\u{1134d}'), ('\u{11350}', '\u{11350}'), ('\u{11357}',
+ '\u{11357}'), ('\u{1135d}', '\u{11363}'), ('\u{11366}', '\u{1136c}'), ('\u{11370}',
+ '\u{11374}'), ('\u{11400}', '\u{1144a}'), ('\u{11450}', '\u{11459}'), ('\u{1145e}',
+ '\u{1145f}'), ('\u{11480}', '\u{114c5}'), ('\u{114c7}', '\u{114c7}'), ('\u{114d0}',
+ '\u{114d9}'), ('\u{11580}', '\u{115b5}'), ('\u{115b8}', '\u{115c0}'), ('\u{115d8}',
+ '\u{115dd}'), ('\u{11600}', '\u{11640}'), ('\u{11644}', '\u{11644}'), ('\u{11650}',
+ '\u{11659}'), ('\u{11680}', '\u{116b8}'), ('\u{116c0}', '\u{116c9}'), ('\u{11700}',
+ '\u{1171a}'), ('\u{1171d}', '\u{1172b}'), ('\u{11730}', '\u{11739}'), ('\u{11800}',
+ '\u{1183a}'), ('\u{118a0}', '\u{118e9}'), ('\u{118ff}', '\u{118ff}'), ('\u{119a0}',
+ '\u{119a7}'), ('\u{119aa}', '\u{119d7}'), ('\u{119da}', '\u{119e1}'), ('\u{119e3}',
+ '\u{119e4}'), ('\u{11a00}', '\u{11a3e}'), ('\u{11a47}', '\u{11a47}'), ('\u{11a50}',
+ '\u{11a99}'), ('\u{11a9d}', '\u{11a9d}'), ('\u{11ac0}', '\u{11af8}'), ('\u{11c00}',
+ '\u{11c08}'), ('\u{11c0a}', '\u{11c36}'), ('\u{11c38}', '\u{11c40}'), ('\u{11c50}',
+ '\u{11c59}'), ('\u{11c72}', '\u{11c8f}'), ('\u{11c92}', '\u{11ca7}'), ('\u{11ca9}',
+ '\u{11cb6}'), ('\u{11d00}', '\u{11d06}'), ('\u{11d08}', '\u{11d09}'), ('\u{11d0b}',
+ '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}',
+ '\u{11d47}'), ('\u{11d50}', '\u{11d59}'), ('\u{11d60}', '\u{11d65}'), ('\u{11d67}',
+ '\u{11d68}'), ('\u{11d6a}', '\u{11d8e}'), ('\u{11d90}', '\u{11d91}'), ('\u{11d93}',
+ '\u{11d98}'), ('\u{11da0}', '\u{11da9}'), ('\u{11ee0}', '\u{11ef6}'), ('\u{12000}',
+ '\u{12399}'), ('\u{12400}', '\u{1246e}'), ('\u{12480}', '\u{12543}'), ('\u{13000}',
+ '\u{1342e}'), ('\u{14400}', '\u{14646}'), ('\u{16800}', '\u{16a38}'), ('\u{16a40}',
+ '\u{16a5e}'), ('\u{16a60}', '\u{16a69}'), ('\u{16ad0}', '\u{16aed}'), ('\u{16af0}',
+ '\u{16af4}'), ('\u{16b00}', '\u{16b36}'), ('\u{16b40}', '\u{16b43}'), ('\u{16b50}',
+ '\u{16b59}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}'), ('\u{16e40}',
+ '\u{16e7f}'), ('\u{16f00}', '\u{16f4a}'), ('\u{16f4f}', '\u{16f87}'), ('\u{16f8f}',
+ '\u{16f9f}'), ('\u{16fe0}', '\u{16fe1}'), ('\u{16fe3}', '\u{16fe3}'), ('\u{17000}',
+ '\u{187f7}'), ('\u{18800}', '\u{18af2}'), ('\u{1b000}', '\u{1b11e}'), ('\u{1b150}',
+ '\u{1b152}'), ('\u{1b164}', '\u{1b167}'), ('\u{1b170}', '\u{1b2fb}'), ('\u{1bc00}',
+ '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}', '\u{1bc88}'), ('\u{1bc90}',
+ '\u{1bc99}'), ('\u{1bc9d}', '\u{1bc9e}'), ('\u{1d165}', '\u{1d169}'), ('\u{1d16d}',
+ '\u{1d172}'), ('\u{1d17b}', '\u{1d182}'), ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}',
+ '\u{1d1ad}'), ('\u{1d242}', '\u{1d244}'), ('\u{1d400}', '\u{1d454}'), ('\u{1d456}',
+ '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}',
+ '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}',
+ '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}',
+ '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}',
+ '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}',
+ '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}',
+ '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}',
+ '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}',
+ '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}',
+ '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1d7ce}', '\u{1d7ff}'), ('\u{1da00}',
+ '\u{1da36}'), ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', '\u{1da75}'), ('\u{1da84}',
+ '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}',
+ '\u{1e006}'), ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), ('\u{1e023}',
+ '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), ('\u{1e100}', '\u{1e12c}'), ('\u{1e130}',
+ '\u{1e13d}'), ('\u{1e140}', '\u{1e149}'), ('\u{1e14e}', '\u{1e14e}'), ('\u{1e2c0}',
+ '\u{1e2f9}'), ('\u{1e800}', '\u{1e8c4}'), ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1e900}',
+ '\u{1e94b}'), ('\u{1e950}', '\u{1e959}'), ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}',
+ '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}',
+ '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}',
+ '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}',
+ '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}',
+ '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}',
+ '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}',
+ '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}',
+ '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}',
+ '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}',
+ '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}',
+ '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}',
+ '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2b820}', '\u{2cea1}'), ('\u{2ceb0}',
+ '\u{2ebe0}'), ('\u{2f800}', '\u{2fa1d}'), ('\u{e0100}', '\u{e01ef}')
+ ];
+
+ pub fn XID_Continue(c: char) -> bool {
+ super::bsearch_range_table(c, XID_Continue_table)
+ }
+
+ pub const XID_Start_table: &[(char, char)] = &[
+ ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'),
+ ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'),
+ ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}',
+ '\u{2ee}'), ('\u{370}', '\u{374}'), ('\u{376}', '\u{377}'), ('\u{37b}', '\u{37d}'),
+ ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}',
+ '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'), ('\u{3f7}', '\u{481}'),
+ ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{559}', '\u{559}'), ('\u{560}',
+ '\u{588}'), ('\u{5d0}', '\u{5ea}'), ('\u{5ef}', '\u{5f2}'), ('\u{620}', '\u{64a}'),
+ ('\u{66e}', '\u{66f}'), ('\u{671}', '\u{6d3}'), ('\u{6d5}', '\u{6d5}'), ('\u{6e5}',
+ '\u{6e6}'), ('\u{6ee}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'),
+ ('\u{710}', '\u{710}'), ('\u{712}', '\u{72f}'), ('\u{74d}', '\u{7a5}'), ('\u{7b1}',
+ '\u{7b1}'), ('\u{7ca}', '\u{7ea}'), ('\u{7f4}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'),
+ ('\u{800}', '\u{815}'), ('\u{81a}', '\u{81a}'), ('\u{824}', '\u{824}'), ('\u{828}',
+ '\u{828}'), ('\u{840}', '\u{858}'), ('\u{860}', '\u{86a}'), ('\u{8a0}', '\u{8b4}'),
+ ('\u{8b6}', '\u{8bd}'), ('\u{904}', '\u{939}'), ('\u{93d}', '\u{93d}'), ('\u{950}',
+ '\u{950}'), ('\u{958}', '\u{961}'), ('\u{971}', '\u{980}'), ('\u{985}', '\u{98c}'),
+ ('\u{98f}', '\u{990}'), ('\u{993}', '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), ('\u{9b2}',
+ '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), ('\u{9bd}', '\u{9bd}'), ('\u{9ce}', '\u{9ce}'),
+ ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e1}'), ('\u{9f0}', '\u{9f1}'), ('\u{9fc}',
+ '\u{9fc}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'), ('\u{a13}', '\u{a28}'),
+ ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}', '\u{a36}'), ('\u{a38}',
+ '\u{a39}'), ('\u{a59}', '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a72}', '\u{a74}'),
+ ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), ('\u{aaa}',
+ '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abd}', '\u{abd}'),
+ ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', '\u{ae1}'), ('\u{af9}', '\u{af9}'), ('\u{b05}',
+ '\u{b0c}'), ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'),
+ ('\u{b32}', '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3d}', '\u{b3d}'), ('\u{b5c}',
+ '\u{b5d}'), ('\u{b5f}', '\u{b61}'), ('\u{b71}', '\u{b71}'), ('\u{b83}', '\u{b83}'),
+ ('\u{b85}', '\u{b8a}'), ('\u{b8e}', '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}',
+ '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'),
+ ('\u{ba8}', '\u{baa}'), ('\u{bae}', '\u{bb9}'), ('\u{bd0}', '\u{bd0}'), ('\u{c05}',
+ '\u{c0c}'), ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'),
+ ('\u{c3d}', '\u{c3d}'), ('\u{c58}', '\u{c5a}'), ('\u{c60}', '\u{c61}'), ('\u{c80}',
+ '\u{c80}'), ('\u{c85}', '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'),
+ ('\u{caa}', '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), ('\u{cbd}', '\u{cbd}'), ('\u{cde}',
+ '\u{cde}'), ('\u{ce0}', '\u{ce1}'), ('\u{cf1}', '\u{cf2}'), ('\u{d05}', '\u{d0c}'),
+ ('\u{d0e}', '\u{d10}'), ('\u{d12}', '\u{d3a}'), ('\u{d3d}', '\u{d3d}'), ('\u{d4e}',
+ '\u{d4e}'), ('\u{d54}', '\u{d56}'), ('\u{d5f}', '\u{d61}'), ('\u{d7a}', '\u{d7f}'),
+ ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', '\u{dbb}'), ('\u{dbd}',
+ '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{e01}', '\u{e30}'), ('\u{e32}', '\u{e32}'),
+ ('\u{e40}', '\u{e46}'), ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e86}',
+ '\u{e8a}'), ('\u{e8c}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{eb0}'),
+ ('\u{eb2}', '\u{eb2}'), ('\u{ebd}', '\u{ebd}'), ('\u{ec0}', '\u{ec4}'), ('\u{ec6}',
+ '\u{ec6}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', '\u{f00}'), ('\u{f40}', '\u{f47}'),
+ ('\u{f49}', '\u{f6c}'), ('\u{f88}', '\u{f8c}'), ('\u{1000}', '\u{102a}'), ('\u{103f}',
+ '\u{103f}'), ('\u{1050}', '\u{1055}'), ('\u{105a}', '\u{105d}'), ('\u{1061}', '\u{1061}'),
+ ('\u{1065}', '\u{1066}'), ('\u{106e}', '\u{1070}'), ('\u{1075}', '\u{1081}'), ('\u{108e}',
+ '\u{108e}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', '\u{10cd}'),
+ ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}',
+ '\u{1256}'), ('\u{1258}', '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'),
+ ('\u{128a}', '\u{128d}'), ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}',
+ '\u{12be}'), ('\u{12c0}', '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'),
+ ('\u{12d8}', '\u{1310}'), ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{1380}',
+ '\u{138f}'), ('\u{13a0}', '\u{13f5}'), ('\u{13f8}', '\u{13fd}'), ('\u{1401}', '\u{166c}'),
+ ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), ('\u{16a0}', '\u{16ea}'), ('\u{16ee}',
+ '\u{16f8}'), ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1711}'), ('\u{1720}', '\u{1731}'),
+ ('\u{1740}', '\u{1751}'), ('\u{1760}', '\u{176c}'), ('\u{176e}', '\u{1770}'), ('\u{1780}',
+ '\u{17b3}'), ('\u{17d7}', '\u{17d7}'), ('\u{17dc}', '\u{17dc}'), ('\u{1820}', '\u{1878}'),
+ ('\u{1880}', '\u{18a8}'), ('\u{18aa}', '\u{18aa}'), ('\u{18b0}', '\u{18f5}'), ('\u{1900}',
+ '\u{191e}'), ('\u{1950}', '\u{196d}'), ('\u{1970}', '\u{1974}'), ('\u{1980}', '\u{19ab}'),
+ ('\u{19b0}', '\u{19c9}'), ('\u{1a00}', '\u{1a16}'), ('\u{1a20}', '\u{1a54}'), ('\u{1aa7}',
+ '\u{1aa7}'), ('\u{1b05}', '\u{1b33}'), ('\u{1b45}', '\u{1b4b}'), ('\u{1b83}', '\u{1ba0}'),
+ ('\u{1bae}', '\u{1baf}'), ('\u{1bba}', '\u{1be5}'), ('\u{1c00}', '\u{1c23}'), ('\u{1c4d}',
+ '\u{1c4f}'), ('\u{1c5a}', '\u{1c7d}'), ('\u{1c80}', '\u{1c88}'), ('\u{1c90}', '\u{1cba}'),
+ ('\u{1cbd}', '\u{1cbf}'), ('\u{1ce9}', '\u{1cec}'), ('\u{1cee}', '\u{1cf3}'), ('\u{1cf5}',
+ '\u{1cf6}'), ('\u{1cfa}', '\u{1cfa}'), ('\u{1d00}', '\u{1dbf}'), ('\u{1e00}', '\u{1f15}'),
+ ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}',
+ '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'),
+ ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}',
+ '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'),
+ ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}',
+ '\u{1ffc}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'),
+ ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}',
+ '\u{2115}'), ('\u{2118}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', '\u{2126}'),
+ ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{2139}'), ('\u{213c}', '\u{213f}'), ('\u{2145}',
+ '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2188}'), ('\u{2c00}', '\u{2c2e}'),
+ ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cee}'), ('\u{2cf2}',
+ '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'),
+ ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2d80}', '\u{2d96}'), ('\u{2da0}',
+ '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'),
+ ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}',
+ '\u{2dde}'), ('\u{3005}', '\u{3007}'), ('\u{3021}', '\u{3029}'), ('\u{3031}', '\u{3035}'),
+ ('\u{3038}', '\u{303c}'), ('\u{3041}', '\u{3096}'), ('\u{309d}', '\u{309f}'), ('\u{30a1}',
+ '\u{30fa}'), ('\u{30fc}', '\u{30ff}'), ('\u{3105}', '\u{312f}'), ('\u{3131}', '\u{318e}'),
+ ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'), ('\u{4e00}',
+ '\u{9fef}'), ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), ('\u{a500}', '\u{a60c}'),
+ ('\u{a610}', '\u{a61f}'), ('\u{a62a}', '\u{a62b}'), ('\u{a640}', '\u{a66e}'), ('\u{a67f}',
+ '\u{a69d}'), ('\u{a6a0}', '\u{a6ef}'), ('\u{a717}', '\u{a71f}'), ('\u{a722}', '\u{a788}'),
+ ('\u{a78b}', '\u{a7bf}'), ('\u{a7c2}', '\u{a7c6}'), ('\u{a7f7}', '\u{a801}'), ('\u{a803}',
+ '\u{a805}'), ('\u{a807}', '\u{a80a}'), ('\u{a80c}', '\u{a822}'), ('\u{a840}', '\u{a873}'),
+ ('\u{a882}', '\u{a8b3}'), ('\u{a8f2}', '\u{a8f7}'), ('\u{a8fb}', '\u{a8fb}'), ('\u{a8fd}',
+ '\u{a8fe}'), ('\u{a90a}', '\u{a925}'), ('\u{a930}', '\u{a946}'), ('\u{a960}', '\u{a97c}'),
+ ('\u{a984}', '\u{a9b2}'), ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e0}', '\u{a9e4}'), ('\u{a9e6}',
+ '\u{a9ef}'), ('\u{a9fa}', '\u{a9fe}'), ('\u{aa00}', '\u{aa28}'), ('\u{aa40}', '\u{aa42}'),
+ ('\u{aa44}', '\u{aa4b}'), ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', '\u{aa7a}'), ('\u{aa7e}',
+ '\u{aaaf}'), ('\u{aab1}', '\u{aab1}'), ('\u{aab5}', '\u{aab6}'), ('\u{aab9}', '\u{aabd}'),
+ ('\u{aac0}', '\u{aac0}'), ('\u{aac2}', '\u{aac2}'), ('\u{aadb}', '\u{aadd}'), ('\u{aae0}',
+ '\u{aaea}'), ('\u{aaf2}', '\u{aaf4}'), ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'),
+ ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), ('\u{ab30}',
+ '\u{ab5a}'), ('\u{ab5c}', '\u{ab67}'), ('\u{ab70}', '\u{abe2}'), ('\u{ac00}', '\u{d7a3}'),
+ ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), ('\u{fa70}',
+ '\u{fad9}'), ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', '\u{fb1d}'),
+ ('\u{fb1f}', '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}',
+ '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'),
+ ('\u{fbd3}', '\u{fc5d}'), ('\u{fc64}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}',
+ '\u{fdc7}'), ('\u{fdf0}', '\u{fdf9}'), ('\u{fe71}', '\u{fe71}'), ('\u{fe73}', '\u{fe73}'),
+ ('\u{fe77}', '\u{fe77}'), ('\u{fe79}', '\u{fe79}'), ('\u{fe7b}', '\u{fe7b}'), ('\u{fe7d}',
+ '\u{fe7d}'), ('\u{fe7f}', '\u{fefc}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'),
+ ('\u{ff66}', '\u{ff9d}'), ('\u{ffa0}', '\u{ffbe}'), ('\u{ffc2}', '\u{ffc7}'), ('\u{ffca}',
+ '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), ('\u{10000}', '\u{1000b}'),
+ ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), ('\u{1003c}', '\u{1003d}'),
+ ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), ('\u{10080}', '\u{100fa}'),
+ ('\u{10140}', '\u{10174}'), ('\u{10280}', '\u{1029c}'), ('\u{102a0}', '\u{102d0}'),
+ ('\u{10300}', '\u{1031f}'), ('\u{1032d}', '\u{1034a}'), ('\u{10350}', '\u{10375}'),
+ ('\u{10380}', '\u{1039d}'), ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', '\u{103cf}'),
+ ('\u{103d1}', '\u{103d5}'), ('\u{10400}', '\u{1049d}'), ('\u{104b0}', '\u{104d3}'),
+ ('\u{104d8}', '\u{104fb}'), ('\u{10500}', '\u{10527}'), ('\u{10530}', '\u{10563}'),
+ ('\u{10600}', '\u{10736}'), ('\u{10740}', '\u{10755}'), ('\u{10760}', '\u{10767}'),
+ ('\u{10800}', '\u{10805}'), ('\u{10808}', '\u{10808}'), ('\u{1080a}', '\u{10835}'),
+ ('\u{10837}', '\u{10838}'), ('\u{1083c}', '\u{1083c}'), ('\u{1083f}', '\u{10855}'),
+ ('\u{10860}', '\u{10876}'), ('\u{10880}', '\u{1089e}'), ('\u{108e0}', '\u{108f2}'),
+ ('\u{108f4}', '\u{108f5}'), ('\u{10900}', '\u{10915}'), ('\u{10920}', '\u{10939}'),
+ ('\u{10980}', '\u{109b7}'), ('\u{109be}', '\u{109bf}'), ('\u{10a00}', '\u{10a00}'),
+ ('\u{10a10}', '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), ('\u{10a19}', '\u{10a35}'),
+ ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'),
+ ('\u{10ac9}', '\u{10ae4}'), ('\u{10b00}', '\u{10b35}'), ('\u{10b40}', '\u{10b55}'),
+ ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', '\u{10b91}'), ('\u{10c00}', '\u{10c48}'),
+ ('\u{10c80}', '\u{10cb2}'), ('\u{10cc0}', '\u{10cf2}'), ('\u{10d00}', '\u{10d23}'),
+ ('\u{10f00}', '\u{10f1c}'), ('\u{10f27}', '\u{10f27}'), ('\u{10f30}', '\u{10f45}'),
+ ('\u{10fe0}', '\u{10ff6}'), ('\u{11003}', '\u{11037}'), ('\u{11083}', '\u{110af}'),
+ ('\u{110d0}', '\u{110e8}'), ('\u{11103}', '\u{11126}'), ('\u{11144}', '\u{11144}'),
+ ('\u{11150}', '\u{11172}'), ('\u{11176}', '\u{11176}'), ('\u{11183}', '\u{111b2}'),
+ ('\u{111c1}', '\u{111c4}'), ('\u{111da}', '\u{111da}'), ('\u{111dc}', '\u{111dc}'),
+ ('\u{11200}', '\u{11211}'), ('\u{11213}', '\u{1122b}'), ('\u{11280}', '\u{11286}'),
+ ('\u{11288}', '\u{11288}'), ('\u{1128a}', '\u{1128d}'), ('\u{1128f}', '\u{1129d}'),
+ ('\u{1129f}', '\u{112a8}'), ('\u{112b0}', '\u{112de}'), ('\u{11305}', '\u{1130c}'),
+ ('\u{1130f}', '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'),
+ ('\u{11332}', '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133d}', '\u{1133d}'),
+ ('\u{11350}', '\u{11350}'), ('\u{1135d}', '\u{11361}'), ('\u{11400}', '\u{11434}'),
+ ('\u{11447}', '\u{1144a}'), ('\u{1145f}', '\u{1145f}'), ('\u{11480}', '\u{114af}'),
+ ('\u{114c4}', '\u{114c5}'), ('\u{114c7}', '\u{114c7}'), ('\u{11580}', '\u{115ae}'),
+ ('\u{115d8}', '\u{115db}'), ('\u{11600}', '\u{1162f}'), ('\u{11644}', '\u{11644}'),
+ ('\u{11680}', '\u{116aa}'), ('\u{116b8}', '\u{116b8}'), ('\u{11700}', '\u{1171a}'),
+ ('\u{11800}', '\u{1182b}'), ('\u{118a0}', '\u{118df}'), ('\u{118ff}', '\u{118ff}'),
+ ('\u{119a0}', '\u{119a7}'), ('\u{119aa}', '\u{119d0}'), ('\u{119e1}', '\u{119e1}'),
+ ('\u{119e3}', '\u{119e3}'), ('\u{11a00}', '\u{11a00}'), ('\u{11a0b}', '\u{11a32}'),
+ ('\u{11a3a}', '\u{11a3a}'), ('\u{11a50}', '\u{11a50}'), ('\u{11a5c}', '\u{11a89}'),
+ ('\u{11a9d}', '\u{11a9d}'), ('\u{11ac0}', '\u{11af8}'), ('\u{11c00}', '\u{11c08}'),
+ ('\u{11c0a}', '\u{11c2e}'), ('\u{11c40}', '\u{11c40}'), ('\u{11c72}', '\u{11c8f}'),
+ ('\u{11d00}', '\u{11d06}'), ('\u{11d08}', '\u{11d09}'), ('\u{11d0b}', '\u{11d30}'),
+ ('\u{11d46}', '\u{11d46}'), ('\u{11d60}', '\u{11d65}'), ('\u{11d67}', '\u{11d68}'),
+ ('\u{11d6a}', '\u{11d89}'), ('\u{11d98}', '\u{11d98}'), ('\u{11ee0}', '\u{11ef2}'),
+ ('\u{12000}', '\u{12399}'), ('\u{12400}', '\u{1246e}'), ('\u{12480}', '\u{12543}'),
+ ('\u{13000}', '\u{1342e}'), ('\u{14400}', '\u{14646}'), ('\u{16800}', '\u{16a38}'),
+ ('\u{16a40}', '\u{16a5e}'), ('\u{16ad0}', '\u{16aed}'), ('\u{16b00}', '\u{16b2f}'),
+ ('\u{16b40}', '\u{16b43}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}'),
+ ('\u{16e40}', '\u{16e7f}'), ('\u{16f00}', '\u{16f4a}'), ('\u{16f50}', '\u{16f50}'),
+ ('\u{16f93}', '\u{16f9f}'), ('\u{16fe0}', '\u{16fe1}'), ('\u{16fe3}', '\u{16fe3}'),
+ ('\u{17000}', '\u{187f7}'), ('\u{18800}', '\u{18af2}'), ('\u{1b000}', '\u{1b11e}'),
+ ('\u{1b150}', '\u{1b152}'), ('\u{1b164}', '\u{1b167}'), ('\u{1b170}', '\u{1b2fb}'),
+ ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}', '\u{1bc88}'),
+ ('\u{1bc90}', '\u{1bc99}'), ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'),
+ ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'),
+ ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'),
+ ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'),
+ ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'),
+ ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'),
+ ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'),
+ ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'),
+ ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'),
+ ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'),
+ ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1e100}', '\u{1e12c}'), ('\u{1e137}', '\u{1e13d}'),
+ ('\u{1e14e}', '\u{1e14e}'), ('\u{1e2c0}', '\u{1e2eb}'), ('\u{1e800}', '\u{1e8c4}'),
+ ('\u{1e900}', '\u{1e943}'), ('\u{1e94b}', '\u{1e94b}'), ('\u{1ee00}', '\u{1ee03}'),
+ ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'),
+ ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'),
+ ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'),
+ ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'),
+ ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'),
+ ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'),
+ ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'),
+ ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'),
+ ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'),
+ ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'),
+ ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', '\u{2a6d6}'),
+ ('\u{2a700}', '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2b820}', '\u{2cea1}'),
+ ('\u{2ceb0}', '\u{2ebe0}'), ('\u{2f800}', '\u{2fa1d}')
+ ];
+
+ pub fn XID_Start(c: char) -> bool {
+ super::bsearch_range_table(c, XID_Start_table)
+ }
+
+}
+
diff --git a/unicode-xid/src/tests.rs b/unicode-xid/src/tests.rs
new file mode 100644
index 0000000..3c9b731
--- /dev/null
+++ b/unicode-xid/src/tests.rs
@@ -0,0 +1,111 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature = "bench")]
+use std::iter;
+#[cfg(feature = "bench")]
+use test::Bencher;
+#[cfg(feature = "bench")]
+use std::prelude::v1::*;
+
+#[cfg(feature = "bench")]
+#[bench]
+fn cargo_is_xid_start(b: &mut Bencher) {
+ let string = iter::repeat('a').take(4096).collect::<String>();
+
+ b.bytes = string.len() as u64;
+ b.iter(|| {
+ string.chars().all(super::UnicodeXID::is_xid_start)
+ });
+}
+
+#[cfg(feature = "bench")]
+#[bench]
+fn stdlib_is_xid_start(b: &mut Bencher) {
+ let string = iter::repeat('a').take(4096).collect::<String>();
+
+ b.bytes = string.len() as u64;
+ b.iter(|| {
+ string.chars().all(char::is_xid_start)
+ });
+}
+
+#[cfg(feature = "bench")]
+#[bench]
+fn cargo_xid_continue(b: &mut Bencher) {
+ let string = iter::repeat('a').take(4096).collect::<String>();
+
+ b.bytes = string.len() as u64;
+ b.iter(|| {
+ string.chars().all(super::UnicodeXID::is_xid_continue)
+ });
+}
+
+#[cfg(feature = "bench")]
+#[bench]
+fn stdlib_xid_continue(b: &mut Bencher) {
+ let string = iter::repeat('a').take(4096).collect::<String>();
+
+ b.bytes = string.len() as u64;
+ b.iter(|| {
+ string.chars().all(char::is_xid_continue)
+ });
+}
+
+#[test]
+fn test_is_xid_start() {
+ let chars = [
+ 'A', 'Z', 'a', 'z',
+ '\u{1000d}', '\u{10026}',
+ ];
+
+ for ch in &chars {
+ assert!(super::UnicodeXID::is_xid_start(*ch), "{}", ch);
+ }
+}
+
+#[test]
+fn test_is_not_xid_start() {
+ let chars = [
+ '\x00', '\x01',
+ '0', '9',
+ ' ', '[', '<', '{', '(',
+ '\u{02c2}', '\u{ffff}',
+ ];
+
+ for ch in &chars {
+ assert!(!super::UnicodeXID::is_xid_start(*ch), "{}", ch);
+ }
+}
+
+#[test]
+fn test_is_xid_continue() {
+ let chars = [
+ '0', '9', 'A', 'Z', 'a', 'z', '_',
+ '\u{1000d}', '\u{10026}',
+ ];
+
+ for ch in &chars {
+ assert!(super::UnicodeXID::is_xid_continue(*ch), "{}", ch);
+ }
+}
+
+#[test]
+fn test_is_not_xid_continue() {
+ let chars = [
+ '\x00', '\x01',
+ ' ', '[', '<', '{', '(',
+ '\u{02c2}', '\u{ffff}',
+ ];
+
+ for &ch in &chars {
+ assert!(!super::UnicodeXID::is_xid_continue(ch), "{}", ch);
+ }
+}